Compare commits

..

154 Commits

Author SHA1 Message Date
orange 63d9ea903e fixed naming in tests 2025-07-07 08:02:35 +03:00
orange 90f6f8eb47 Merge pull request #45 from luadebug/patch-1
Check for ImGUI dependency in omathConfig.cmake.in
2025-07-07 05:30:19 +03:00
Saikari d187cd67d4 Update omathConfig.cmake.in 2025-07-07 04:53:56 +03:00
orange f489ec7a85 Updates CMake export target and namespace.
Updates the CMake export target and namespace to use the project name,
improving consistency and avoiding naming conflicts.

Adds a simple diagram to the triangle header file.
2025-07-06 11:14:46 +03:00
orange cc2754a985 Renames library target to project name
Updates the CMakeLists.txt to use the project name as the library target name instead of hardcoding "omath".

This change ensures consistency and avoids potential conflicts when integrating the library into other projects.
It also aligns the target naming with CMake best practices.
2025-07-06 11:07:15 +03:00
orange efca121348 added new method 2025-06-23 06:14:17 +03:00
orange 6b900f2855 fix 2025-06-17 21:34:25 +03:00
orange 681ea99d7b added banner to repo 2025-06-17 21:33:39 +03:00
orange d196e4d9a8 fixed example 2025-06-16 01:40:14 +03:00
orange 750647a9d5 Merge pull request #39 from orange-cpp/u/orange-cpp/writerside
U/orange cpp/writerside
2025-05-21 16:58:19 +03:00
orange 37e1ac7b88 fixed stuff 2025-05-21 16:57:17 +03:00
orange 77fcb6faa4 added text 2025-05-21 16:47:15 +03:00
orange e95567c82c fix 2025-05-21 16:47:15 +03:00
orange ac3266644b fix 2025-05-21 16:47:15 +03:00
orange 15463ba09c improved intro 2025-05-21 16:47:15 +03:00
orange ef4157ffbb added new topic 2025-05-21 16:47:15 +03:00
orange 4c4d6c87ba stipped away text 2025-05-21 16:47:15 +03:00
orange 69a0323097 added files 2025-05-21 16:47:15 +03:00
orange b989c66088 fixed version 2025-05-13 09:48:46 +03:00
orange fb7cb0e800 improved naming 2025-05-13 09:47:08 +03:00
orange e2322960b7 added noexcept 2025-05-13 09:34:39 +03:00
orange c8963668f3 removed even float type from vector classes 2025-05-13 09:22:23 +03:00
orange 91525ac149 Merge pull request #44 from orange-cpp/feature/noexcept
Feature/noexcept
2025-05-05 02:34:43 +03:00
orange 505fe6f3a8 added more noexcept 2025-05-05 02:24:23 +03:00
orange ba2c60389f added more noexcept 2025-05-05 01:46:50 +03:00
orange 45c7ff131f added noexcept 2025-05-05 01:16:12 +03:00
orange 27b130345c added noexcept for color and angles 2025-05-04 19:16:49 +03:00
orange c9796e4145 added noexcept for vector types 2025-05-04 19:13:26 +03:00
orange 4b14e1902b changed license to zlib 2025-05-04 19:05:10 +03:00
orange 399ded102d removed useless source files 2025-05-04 19:03:18 +03:00
orange ef93e9904c fixed style 2025-05-04 18:54:33 +03:00
orange 1d22901bf5 removed pow 2025-05-04 18:07:35 +03:00
orange 8b8ed495d5 fixed clang format 2025-05-04 17:42:32 +03:00
orange b4891ed057 Update README.md 2025-05-04 00:55:35 +03:00
orange 7009d998af Update cmake-multi-platform.yml
switched to clang

Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
Update cmake-multi-platform.yml
added runtime dir

fix
2025-05-03 22:51:46 +03:00
orange 2f5423bab7 Merge pull request #43 from orange-cpp/orange-cpp-ci
Create cmake-multi-platform.yml
2025-05-03 22:04:37 +03:00
orange 99325aa983 Create cmake-multi-platform.yml 2025-05-03 22:04:10 +03:00
orange 34f363e8c6 bugfix 2025-05-03 21:36:16 +03:00
orange 1773a3a09f Merge pull request #42 from orange-cpp/feature/new-codestyle
Feature/new codestyle
2025-05-03 20:59:06 +03:00
orange cf2243a537 fix 2025-05-03 20:51:50 +03:00
orange 6df9d59fe9 fixed style 2025-05-03 20:38:58 +03:00
orange 4406e1e461 changed code style 2025-05-03 20:31:59 +03:00
orange fd37a252f8 patched clang format 2025-05-03 16:50:29 +03:00
orange 59815b52bb updated clang format 2025-05-03 16:39:38 +03:00
orange fcc6a38fba Merge pull request #41 from orange-cpp/u/improved-cmake
improved cmake, removed useless cmake files
2025-04-30 21:31:34 +03:00
orange 01b7256e98 improved cmake, removed useless cmake files 2025-04-30 21:26:25 +03:00
orange c41ede1b74 moved installation stuff to INSTALL.md 2025-04-30 18:15:46 +03:00
orange 58dacfb36b Merge pull request #40 from orange-cpp/u/orange/inverted-matrix
U/orange/inverted matrix
2025-04-29 20:53:02 +03:00
orange 4dbddd0a34 style fix 2025-04-29 20:52:41 +03:00
orange ef787fd4e7 added test case 2025-04-29 20:49:59 +03:00
orange efadf3a918 added inverse method 2025-04-29 20:33:39 +03:00
orange 468261d3f1 added additional methods 2025-04-29 20:10:17 +03:00
orange 733ef19460 fixed infinite recursion in compile time 2025-04-29 20:08:27 +03:00
orange 9de444bda0 fixed gimba lock for unity 2025-04-26 00:52:46 +03:00
orange 34621ad171 fixed gimba lock for opengl camera 2025-04-26 00:32:53 +03:00
orange a36b54610b resetting state 2025-04-25 23:52:10 +03:00
orange 0b4730be02 removed .idea folder 2025-04-23 02:48:45 +03:00
orange 0042be5743 added credits 2025-04-23 02:46:08 +03:00
orange 93e7aef2f5 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
orange d9e8fad2fc reset to default 2025-04-18 16:55:07 +03:00
orange cdb2ca023a updated readme 2025-04-18 16:53:53 +03:00
orange 6d65e1f1c3 improved tests 2025-04-18 16:36:22 +03:00
Vladislav Alpatov 6a7d328a7c improved line tracer 2025-04-18 16:00:23 +03:00
orange 13753cab81 improved line trace and box primitive 2025-04-18 13:56:08 +03:00
orange 88f4db6caf switched to polygons 2025-04-18 12:34:24 +03:00
orange d9ccfe83ae fixed code style 2025-04-18 12:11:43 +03:00
orange 80e3cadb67 added ratio param 2025-04-18 01:33:47 +03:00
orange 505a8cce9a added new build option 2025-04-18 00:51:07 +03:00
orange 5ff57f9ffa added box 2025-04-18 00:43:46 +03:00
orange c46dc436fc fixed include 2025-04-16 20:35:17 +03:00
orange 57b6e9da50 Merge pull request #37 from orange-cpp/u/engine_rotation_mats
U/engine rotation mats
2025-04-16 23:21:58 +03:00
orange 06b891c827 improved openg gl rotation matrix, added tests 2025-04-16 19:11:02 +03:00
orange 2bface1c49 added tests for source 2025-04-16 18:53:31 +03:00
orange 97f38af2b5 added unit tests 2025-04-16 18:35:50 +03:00
orange 622c2866d9 fixed formating 2025-04-16 17:52:57 +03:00
orange 7642936716 removed method from Mat added method for unity 2025-04-16 17:52:19 +03:00
orange e0d61fa486 added func
added rotation matrix for opengl

updated unit tests
2025-04-16 17:40:00 +03:00
orange f1f2aeb1b9 added func
added rotation matrix for opengl
2025-04-16 17:40:00 +03:00
orange 51f85e4e3a removed whitespaces 2025-04-16 12:21:10 +03:00
orange 790e6919f7 added missing header 2025-04-13 23:15:27 +03:00
orange 24f757eb68 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
orange 582a591e4b fixed tests 2025-04-12 00:04:07 +03:00
orange 07c1a6670d added const method to mat 2025-04-11 23:57:56 +03:00
orange 83f14c89f4 added new build option 2025-04-11 23:54:56 +03:00
orange bda3edd596 improved naming 2025-04-11 23:30:07 +03:00
orange 4cca66878b improvement 2025-04-11 23:20:16 +03:00
orange f66e1e4a50 replaced with STL relization 2025-04-11 23:10:02 +03:00
orange 3cfa340ab3 added missing header 2025-04-11 22:59:56 +03:00
orange 63a178a893 disabled tests 2025-04-05 20:03:39 +03:00
Orange 94d474200a updated read me 2025-04-05 13:28:28 +03:00
Orange ad5dad7295 added include 2025-04-05 13:20:18 +03:00
Orange eb1df5af8d fixed for clang 2025-04-05 13:00:00 +03:00
orange 4586e32bc8 oops 2025-03-29 22:03:30 +03:00
orange 7bc81835eb fixed in some cases confilcting with win api 2025-03-29 21:57:35 +03:00
orange 32b099d480 fix 2025-03-29 18:20:17 +03:00
orange 8271dd93f6 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
orange 03f816475b added new methods 2025-03-29 05:41:55 +03:00
orange 7e580506b6 fixed style 2025-03-29 04:00:35 +03:00
orange 0d2198d251 added vcpkg imgui package auto link 2025-03-29 01:56:09 +03:00
orange 5a1ad408bb added new option 2025-03-29 01:53:04 +03:00
orange 4e71888f27 improved imgui handling 2025-03-24 21:48:51 +03:00
orange d30c5be50f fixed for clang 2025-03-24 06:48:51 +03:00
orange 54ef1abb21 Update README.md 2025-03-24 06:46:02 +03:00
orange 47e8bc1a04 fixed unity view matrix building 2025-03-24 06:30:09 +03:00
orange d1c48762d8 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
orange ff492c04a9 fix 2025-03-23 01:17:05 +03:00
orange 58b67518b4 removed comment 2025-03-23 01:12:46 +03:00
orange 2f2c0557c8 name fix 2025-03-23 01:06:36 +03:00
orange e487ddd11b naming fixed 2025-03-23 01:02:11 +03:00
orange d2e67b7f86 fix 2025-03-23 00:57:58 +03:00
orange d6a399fa65 uncommented test 2025-03-23 00:52:12 +03:00
orange 5a0e88c2ca fix 2025-03-22 17:41:01 +03:00
orange 620ea44b06 improved camera 2025-03-22 17:39:40 +03:00
orange de968ee03b updated formulas 2025-03-22 08:36:06 +03:00
orange cbc0a13a79 added unity engine tests 2025-03-22 08:12:16 +03:00
orange d9fe60b505 added camera files 2025-03-22 04:26:54 +03:00
orange 2e814e259c Update README.md 2025-03-21 05:31:44 +03:00
orange d8c653d730 fixed tests includes 2025-03-21 04:58:28 +03:00
orange 213be0de82 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
orange 5c8f730ac7 style fix 2025-03-21 04:48:38 +03:00
orange 9383fd37fc fix 2025-03-21 04:47:01 +03:00
orange 4153932a4f fix 2025-03-21 04:46:23 +03:00
orange faa258ade0 fixed name 2025-03-21 04:45:02 +03:00
orange 7102faa6f7 fixed example 2025-03-21 04:43:57 +03:00
orange 756bcef6e1 fixed include names 2025-03-21 04:40:59 +03:00
orange d5d1260784 changed source files naming 2025-03-21 04:30:17 +03:00
orange e4eb27c6de change 2025-03-21 04:21:31 +03:00
Vladislav Alpatov 5fdf3dad16 renamed headers 2025-03-21 04:17:42 +03:00
orange 3a1533eccb Merge pull request #32 from orange-cpp/u/orange-cpp/examples
U/orange cpp/examples
2025-03-19 20:17:45 +03:00
orange 6c5e31c767 disabled tests by default 2025-03-19 20:13:06 +03:00
orange 1b2822275f removed inline functions 2025-03-19 20:07:44 +03:00
orange adab187ce7 added example 2025-03-19 19:16:22 +03:00
Vladislav Alpatov 00a9e41477 added some files 2025-03-19 18:58:35 +03:00
orange 7de64c804c added alias 2025-03-19 18:50:47 +03:00
orange dbd7eb7d5f improved print method 2025-03-19 00:56:56 +03:00
orange 2abdeb3d7f Update README.md 2025-03-17 18:20:40 +03:00
orange 6f621482b8 Merge pull request #31 from orange-cpp/u/orange-cpp/IWEngine
Added Infinity Ward Engine Support
2025-03-17 09:20:51 +03:00
orange 89356546ca updated comment 2025-03-17 09:14:42 +03:00
orange 4df0d38257 added magic number 2025-03-17 08:59:41 +03:00
orange f788a60e14 added iw engine files 2025-03-17 07:20:13 +03:00
orange 3c104cd228 changed naming of engines section 2025-03-17 05:27:00 +03:00
orange 371712c889 Merge pull request #30 from orange-cpp/u/orange-cpp/imgui-integration
ImGUI Vector integration
2025-03-17 04:12:39 +03:00
orange 1d0eca6808 changed default option 2025-03-17 04:11:49 +03:00
orange 26f3009fed fix 2025-03-17 04:07:21 +03:00
orange 94f69760a7 added convertors 2025-03-17 03:56:09 +03:00
orange 742344e221 fix 2025-03-17 02:41:08 +03:00
orange 6daf23e4cb unit tests buid off by defalut 2025-03-15 19:13:06 +03:00
orange 442e28ac02 fixed Vec3 Vec4 2025-03-15 19:11:31 +03:00
orange 271905364d added explicit constructor for angle and comment for angle 2025-03-15 18:57:41 +03:00
orange ebef8f48ca improved mat & camera interface 2025-03-15 18:53:18 +03:00
orange 544f5bda97 fixed members inititalization miss match 2025-03-14 19:43:50 +03:00
Vladislav Alpatov cf6eb0fd60 patch 2025-03-01 21:32:02 +03:00
Vladislav Alpatov 9d30d7e7c8 added option to disable avx2 2025-03-01 21:30:53 +03:00
Vladislav Alpatov f677eaa08d fixed for clang support 2025-03-01 21:22:44 +03:00
150 changed files with 4919 additions and 3467 deletions
+40 -38
View File
@@ -1,62 +1,64 @@
# Generated from CLion C/C++ Code Style settings # Generated by CLion for Stroustrup
--- # The Stroustrup style, named after Bjarne Stroustrup, the creator of C++, is similar to the K&R style but differs
Language: Cpp # in its treatment of the class definitions and the placement of braces in certain contexts. The opening brace is
# placed on the same line as the control statement, and the closing brace is on its own line.
BasedOnStyle: LLVM BasedOnStyle: LLVM
AccessModifierOffset: -4 AccessModifierOffset: -4
AlignConsecutiveAssignments: false AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: false AlignConsecutiveBitFields: None
AlignOperands: true AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
AlignTrailingComments: false AlignTrailingComments: false
AllowShortBlocksOnASingleLine: false AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None AllowShortFunctionsOnASingleLine: None
AlwaysBreakTemplateDeclarations: Yes AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
BreakTemplateDeclarations: Leave
BreakBeforeBraces: Custom
BraceWrapping: BraceWrapping:
AfterCaseLabel: true AfterCaseLabel: true
AfterClass: true AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true AfterFunction: true
AfterControlStatement: true
SplitEmptyFunction: true
AfterEnum: true
AfterNamespace: true AfterNamespace: true
AfterStruct: true AfterStruct: true
AfterUnion: true AfterUnion: true
AfterExternBlock: true AfterExternBlock: true
BeforeCatch: false BeforeCatch: true
BeforeElse: false BeforeElse: true
BeforeLambdaBody: true BeforeLambdaBody: true
BeforeWhile: false BeforeWhile: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true SplitEmptyRecord: true
SplitEmptyNamespace: true SplitEmptyNamespace: true
BreakBeforeBraces: Custom BreakBeforeBinaryOperators: NonAssignment
BreakConstructorInitializers: AfterColon BreakBeforeConceptDeclarations: false
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 120 ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: false IncludeBlocks: Merge
ContinuationIndentWidth: 8 IndentExternBlock: Indent
IncludeCategories: IndentRequiresClause: false
- Regex: '^<.*'
Priority: 1
- Regex: '^".*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentWidth: 4 IndentWidth: 4
InsertNewlineAtEOF: true ContinuationIndentWidth: 8
MacroBlockBegin: '' KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All NamespaceIndentation: All
PointerAlignment: Left PointerAlignment: Left
SpaceAfterCStyleCast: true SortUsingDeclarations: true
SpaceAfterTemplateKeyword: false SpaceAfterTemplateKeyword: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterForeachMacros: true
AfterIfMacros: true
AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: false SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyParentheses: false SpaceInEmptyParentheses: false
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInCStyleCastParentheses: false SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInParentheses: false SpacesInParentheses: false
TabWidth: 4
...
Binary file not shown.
@@ -0,0 +1,79 @@
name: Omath CI (Arch Linux / Windows)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
##############################################################################
# 1) ARCH LINUX Clang / Ninja
##############################################################################
jobs:
arch-build-and-test:
name: Arch Linux (Clang)
runs-on: ubuntu-latest
container: archlinux:latest
steps:
- name: Install basic tool-chain with pacman
shell: bash
run: |
pacman -Sy --noconfirm archlinux-keyring
pacman -Syu --noconfirm --needed \
git base-devel clang cmake ninja
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Configure (cmake --preset)
shell: bash
run: cmake --preset linux-release -DOMATH_BUILD_TESTS=ON
- name: Build
shell: bash
run: cmake --build cmake-build/build/linux-release --target all
- name: Run unit_tests
shell: bash
run: ./out/Release/unit_tests
##############################################################################
# 2) Windows MSVC / Ninja
##############################################################################
windows-build-and-test:
name: Windows (MSVC)
runs-on: windows-latest
steps:
- name: Checkout repository (with sub-modules)
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Ninja
uses: seanmiddleditch/gha-setup-ninja@v4
- name: Set up MSVC developer command-prompt
uses: ilammy/msvc-dev-cmd@v1
- name: Configure (cmake --preset)
shell: bash
run: cmake --preset windows-release -DOMATH_BUILD_TESTS=ON
- name: Build
shell: bash
run: cmake --build cmake-build/build/windows-release --target all
- name: Run unit_tests.exe
shell: bash
run: ./out/Release/unit_tests.exe
+1
View File
@@ -1,3 +1,4 @@
/cmake-build/ /cmake-build/
/.idea /.idea
/out /out
*.DS_Store
-8
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>
Generated
-2
View File
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />
Generated
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
</component>
</project>
+86 -31
View File
@@ -1,47 +1,102 @@
cmake_minimum_required(VERSION 3.26) cmake_minimum_required(VERSION 3.26)
project(omath VERSION 1.0.1 LANGUAGES CXX) project(omath VERSION 3.0.2 LANGUAGES CXX)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
option(OMATH_BUILD_TESTS "Build unit tests" ON) option(OMATH_BUILD_TESTS "Build unit tests" OFF)
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
option(OMATH_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)
file(GLOB_RECURSE OMATH_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
file(GLOB_RECURSE OMATH_HEADERS CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
if (OMATH_BUILD_AS_SHARED_LIBRARY) if (OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(omath SHARED source/Vector3.cpp) add_library(${PROJECT_NAME} SHARED ${OMATH_SOURCES} ${OMATH_HEADERS})
else() else ()
add_library(omath STATIC source/Matrix.cpp) add_library(${PROJECT_NAME} STATIC ${OMATH_SOURCES} ${OMATH_HEADERS})
endif() endif ()
set_target_properties(omath PROPERTIES message(STATUS "[OMATH]: Building on ${CMAKE_HOST_SYSTEM_NAME}")
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
if (OMATH_IMGUI_INTEGRATION)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_IMGUI_INTEGRATION)
# IMGUI is being linked as submodule
if (TARGET imgui)
target_link_libraries(${PROJECT_NAME} 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(${PROJECT_NAME} PUBLIC imgui::imgui)
endif ()
endif ()
if (OMATH_USE_AVX2)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_USE_AVX2)
endif ()
if (OMATH_SUPRESS_SAFETY_CHECKS)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_SUPRESS_SAFETY_CHECKS)
endif ()
set_target_properties(${PROJECT_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20
CXX_STANDARD 23 CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON) CXX_STANDARD_REQUIRED ON)
if (OMATH_USE_UNITY_BUILD)
set_target_properties(${PROJECT_NAME} PROPERTIES
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20)
endif ()
target_compile_features(omath PUBLIC cxx_std_23) if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
set_target_properties(${PROJECT_NAME} PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(${PROJECT_NAME} PRIVATE -mavx2 -mfma)
endif ()
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
add_subdirectory(source) if (OMATH_BUILD_TESTS)
if(OMATH_BUILD_TESTS)
add_subdirectory(extlibs) 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(${PROJECT_NAME} PRIVATE /W4 /WX)
elseif(OMATH_THREAT_WARNING_AS_ERROR) elseif (OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(omath PRIVATE -Wall -Wextra -Wpedantic -Werror) target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -Werror)
endif() endif ()
target_include_directories(omath target_include_directories(${PROJECT_NAME}
PUBLIC PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # Use this path when building the project $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # Use this path when building the project
$<INSTALL_INTERFACE:include> # Use this path when the project is installed $<INSTALL_INTERFACE:include> # Use this path when the project is installed
@@ -51,21 +106,21 @@ target_include_directories(omath
# Installation rules # Installation rules
# Install the library # Install the library
install(TARGETS omath install(TARGETS ${PROJECT_NAME}
EXPORT omathTargets EXPORT ${PROJECT_NAME}Targets
ARCHIVE DESTINATION lib COMPONENT omath # For static libraries ARCHIVE DESTINATION lib COMPONENT ${PROJECT_NAME} # For static libraries
LIBRARY DESTINATION lib COMPONENT omath # For shared libraries LIBRARY DESTINATION lib COMPONENT ${PROJECT_NAME} # For shared libraries
RUNTIME DESTINATION bin COMPONENT omath # For executables (on Windows) RUNTIME DESTINATION bin COMPONENT ${PROJECT_NAME} # For executables (on Windows)
) )
# Install headers as part of omath_component # Install headers as part of omath_component
install(DIRECTORY include/ DESTINATION include COMPONENT omath) install(DIRECTORY include/ DESTINATION include COMPONENT ${PROJECT_NAME})
# Export omath target for CMake find_package support, also under omath_component # Export omath target for CMake find_package support, also under omath_component
install(EXPORT omathTargets install(EXPORT ${PROJECT_NAME}Targets
FILE omathTargets.cmake FILE ${PROJECT_NAME}Targets.cmake
NAMESPACE omath:: NAMESPACE ${PROJECT_NAME}::
DESTINATION lib/cmake/omath COMPONENT omath DESTINATION lib/cmake/${PROJECT_NAME} COMPONENT ${PROJECT_NAME}
) )
@@ -80,12 +135,12 @@ write_basic_package_version_file(
configure_package_config_file( configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/omathConfig.cmake.in" # Path to the .in file "${CMAKE_CURRENT_SOURCE_DIR}/cmake/omathConfig.cmake.in" # Path to the .in file
"${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" # Output path for the generated file "${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" # Output path for the generated file
INSTALL_DESTINATION lib/cmake/omath INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
) )
# Install the generated config files # Install the generated config files
install(FILES install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/omathConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/omathConfigVersion.cmake"
DESTINATION lib/cmake/omath DESTINATION lib/cmake/${PROJECT_NAME}
) )
+34 -2
View File
@@ -40,8 +40,8 @@
"binaryDir": "${sourceDir}/cmake-build/build/${presetName}", "binaryDir": "${sourceDir}/cmake-build/build/${presetName}",
"installDir": "${sourceDir}/cmake-build/install/${presetName}", "installDir": "${sourceDir}/cmake-build/install/${presetName}",
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER": "gcc", "CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "g++" "CMAKE_CXX_COMPILER": "clang++"
}, },
"condition": { "condition": {
"type": "equals", "type": "equals",
@@ -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
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>
+54
View File
@@ -0,0 +1,54 @@
# 📥Installation Guide
## <img width="28px" src="https://vcpkg.io/assets/mark/mark.svg" /> Using vcpkg
**Note**: Support vcpkg for package management
1. Install [vcpkg](https://github.com/microsoft/vcpkg)
2. Run the following command to install the orange-math package:
```
vcpkg install orange-math
```
CMakeLists.txt
```cmake
find_package(omath CONFIG REQUIRED)
target_link_libraries(main PRIVATE omath::omath)
```
For detailed commands on installing different versions and more information, please refer to Microsoft's [official instructions](https://learn.microsoft.com/en-us/vcpkg/get_started/overview).
## <img width="28px" src="https://upload.wikimedia.org/wikipedia/commons/e/ef/CMake_logo.svg?" /> Build from source using CMake
1. **Preparation**
Install needed tools: cmake, clang, git, msvc (windows only).
1. **Linux:**
```bash
sudo pacman -Sy cmake ninja clang git
```
2. **MacOS:**
```bash
brew install llvm git cmake ninja
```
3. **Windows:**
Install Visual Studio from [here](https://visualstudio.microsoft.com/downloads/) and Git from [here](https://git-scm.com/downloads).
Use x64 Native Tools shell to execute needed commands down below.
2. **Clone the repository:**
```bash
git clone https://github.com/orange-cpp/omath.git
```
3. **Navigate to the project directory:**
```bash
cd omath
```
4. **Build the project using CMake:**
```bash
cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target omath -j 6
```
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
| Platform Name | Build Config |
|---------------|---------------|
| windows | release/debug |
| linux | release/debug |
| darwin | release/debug |
+14 -6
View File
@@ -1,9 +1,17 @@
The MIT License (MIT) Copyright (C) 2024-2025 Orange++ <orange-cpp@yandex.ru>
Copyright (c) 2024 Orange++ This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+30 -39
View File
@@ -1,59 +1,46 @@
<div align = center> <div align = center>
![banner](https://i.imgur.com/sjtpKi8.png) ![banner](https://github.com/orange-cpp/omath/blob/main/.github/images/banner.png?raw=true)
![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)
![GitHub top language](https://img.shields.io/github/languages/top/orange-cpp/omath) ![GitHub top language](https://img.shields.io/github/languages/top/orange-cpp/omath)
[![CodeFactor](https://www.codefactor.io/repository/github/orange-cpp/omath/badge)](https://www.codefactor.io/repository/github/orange-cpp/omath) [![CodeFactor](https://www.codefactor.io/repository/github/orange-cpp/omath/badge)](https://www.codefactor.io/repository/github/orange-cpp/omath)
![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/orange-cpp/omath/cmake-multi-platform.yml)
![GitHub forks](https://img.shields.io/github/forks/orange-cpp/omath) ![GitHub forks](https://img.shields.io/github/forks/orange-cpp/omath)
</div> </div>
Oranges's Math Library (omath) is a comprehensive, open-source library aimed at providing efficient, reliable, and versatile mathematical functions and algorithms. Developed primarily in C++, this library is designed to cater to a wide range of mathematical operations essential in scientific computing, engineering, and academic research. 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
### Prerequisites | ENGINE | SUPPORT |
- C++ Compiler |----------|---------|
- CMake (for building the project) | Source | ✅YES |
| Unity | ✅YES |
| IWEngine | ✅YES |
| Unreal | ❌NO |
## Supported Operating Systems
| OS | SUPPORT |
|----------------|---------|
| Windows 10/11 | ✅YES |
| Linux | ✅YES |
| Darwin (MacOS) | ✅YES |
## ⏬ Installation
Please read our [installation guide](https://github.com/orange-cpp/omath/blob/main/INSTALL.md). If this link doesn't work check out INSTALL.md file.
### 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:
```
git clone https://github.com/orange-cpp/omath.git
```
2. Navigate to the project directory:
```
cd omath
```
3. Build the project using CMake:
```
cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target omath -j 6
```
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
## ❔ Usage ## ❔ Usage
Simple world to screen function Simple world to screen function
```c++ ```c++
@@ -65,15 +52,19 @@ 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
+4
View File
@@ -2,6 +2,10 @@
include(CMakeFindDependencyMacro) include(CMakeFindDependencyMacro)
if (@OMATH_IMGUI_INTEGRATION@)
find_dependency(imgui CONFIG)
endif()
# 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) check_required_components(omath)
+4
View File
@@ -0,0 +1,4 @@
project(examples)
add_executable(ExampleProjectionMatrixBuilder example_proj_mat_builder.cpp)
target_link_libraries(ExampleProjectionMatrixBuilder PRIVATE omath::omath)
+40
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 view_port_width = 0;
float view_port_height = 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 >> view_port_width;
std::print("Enter camera screen height: ");
std::cin >> view_port_height;
const auto mat =
omath::opengl_engine::calc_perspective_projection_matrix(fov, view_port_width / view_port_height, near, far);
std::print("{}", mat.to_string());
};
+17
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> create_box(const Vector3<float>& top, const Vector3<float>& bottom,
const Vector3<float>& dir_forward, const Vector3<float>& dir_right,
float ratio = 4.f) noexcept;
}
-63
View File
@@ -1,63 +0,0 @@
//
// Created by vlad on 11/6/23.
//
#pragma once
#include <numbers>
#include <cmath>
namespace omath::angles
{
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr Type RadiansToDegrees(const Type& radians)
{
return radians * (Type(180) / std::numbers::pi_v<Type>);
}
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr Type DegreesToRadians(const Type& degrees)
{
return degrees * (std::numbers::pi_v<Type> / Type(180));
}
template<class type>
requires std::is_floating_point_v<type>
[[nodiscard]] type HorizontalFovToVertical(const type& horFov, const type& aspect)
{
const auto fovRad = DegreesToRadians(horFov);
const auto vertFov = type(2) * std::atan(std::tan(fovRad / type(2)) / aspect);
return RadiansToDegrees(vertFov);
}
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] Type VerticalFovToHorizontal(const Type& vertFov, const Type& aspect)
{
const auto fovRad = DegreesToRadians(vertFov);
const auto horFov = Type(2) * std::atan(std::tan(fovRad / Type(2)) * aspect);
return RadiansToDegrees(horFov);
}
template<class Type>
requires std::is_arithmetic_v<Type>
[[nodiscard]] Type WrapAngle(const Type& angle, const Type& min, const Type& max)
{
if (angle <= max && angle >= min)
return angle;
const Type range = max - min;
Type wrappedAngle = std::fmod(angle - min, range);
if (wrappedAngle < 0)
wrappedAngle += range;
return wrappedAngle + min;
}
}
-122
View File
@@ -1,122 +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<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() : 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};
}
}
-421
View File
@@ -1,421 +0,0 @@
//
// Created by vlad on 9/29/2024.
//
#pragma once
#include <algorithm>
#include <array>
#include <sstream>
#include <stdexcept>
#include <utility>
#include "Vector3.hpp"
namespace omath
{
struct MatSize
{
size_t rows, columns;
};
enum class MatStoreType : uint8_t
{
ROW_MAJOR = 0,
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>
requires std::is_arithmetic_v<Type>
class Mat final
{
public:
constexpr Mat()
{
Clear();
}
constexpr static MatStoreType GetStoreOrdering()
{
return StoreType;
}
constexpr Mat(const std::initializer_list<std::initializer_list<Type>>& rows)
{
if (rows.size() != Rows)
throw std::invalid_argument("Initializer list rows size does not match template parameter Rows");
auto rowIt = rows.begin();
for (size_t i = 0; i < Rows; ++i, ++rowIt)
{
if (rowIt->size() != Columns)
throw std::invalid_argument(
"All rows must have the same number of columns as template parameter Columns");
auto colIt = rowIt->begin();
for (size_t j = 0; j < Columns; ++j, ++colIt)
{
At(i, j) = std::move(*colIt);
}
}
}
constexpr explicit Mat(const Type* rawData)
{
std::copy_n(rawData, Rows * Columns, m_data.begin());
}
constexpr Mat(const Mat& other) noexcept
{
m_data = other.m_data;
}
constexpr Type& operator[](const size_t row, const size_t col)
{
return At(row, col);
}
constexpr Mat(Mat&& other) noexcept
{
m_data = std::move(other.m_data);
}
[[nodiscard]]
static constexpr size_t RowCount() noexcept
{
return Rows;
}
[[nodiscard]]
static constexpr size_t ColumnsCount() noexcept
{
return Columns;
}
[[nodiscard]]
static consteval MatSize Size() noexcept
{
return {Rows, Columns};
}
[[nodiscard]] constexpr const Type& At(const size_t rowIndex, const size_t columnIndex) const
{
if (rowIndex >= Rows || columnIndex >= Columns)
throw std::out_of_range("Index out of range");
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return m_data[rowIndex * Columns + columnIndex];
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
return m_data[rowIndex + columnIndex * Rows];
else
{
static_assert(false, "Invalid matrix access convention");
std::unreachable();
}
}
[[nodiscard]] constexpr Type& At(const size_t rowIndex, const size_t columnIndex)
{
return const_cast<Type&>(std::as_const(*this).At(rowIndex, columnIndex));
}
[[nodiscard]]
constexpr Type Sum() const noexcept
{
Type sum = 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
{
Set(0);
}
constexpr void Set(const Type& value) noexcept
{
std::ranges::fill(m_data, value);
}
// Operator overloading for multiplication with another Mat
template<size_t OtherColumns>
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{
Mat<Rows, OtherColumns, Type, StoreType> result;
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < OtherColumns; ++j)
{
Type sum = 0;
for (size_t k = 0; k < Columns; ++k)
sum += At(i, k) * other.At(k, j);
result.At(i, j) = sum;
}
return result;
}
constexpr Mat& operator*=(const Type& f) noexcept
{
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
At(i, j) *= f;
return *this;
}
template<size_t OtherColumns>
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*=(const Mat<Columns, OtherColumns, Type, StoreType>& other)
{
return *this = *this * other;
}
constexpr Mat operator*(const Type& f) const noexcept
{
Mat result(*this);
result *= f;
return result;
}
constexpr Mat& operator/=(const Type& f) noexcept
{
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
At(i, j) /= f;
return *this;
}
constexpr Mat operator/(const Type& f) const noexcept
{
Mat result(*this);
result /= f;
return result;
}
constexpr Mat& operator=(const Mat& other) noexcept
{
if (this == &other)
return *this;
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;
}
constexpr Mat& operator=(Mat&& other) noexcept
{
if (this == &other)
return *this;
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;
}
[[nodiscard]]
constexpr Mat<Columns, Rows, Type, StoreType> Transposed() const noexcept
{
Mat<Columns, Rows, Type, StoreType> transposed;
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
transposed.At(j, i) = At(i, j);
return transposed;
}
[[nodiscard]]
constexpr Type Determinant() const
{
static_assert(Rows == Columns, "Determinant is only defined for square matrices.");
if constexpr (Rows == 1)
return At(0, 0);
else if constexpr (Rows == 2)
return At(0, 0) * At(1, 1) - At(0, 1) * At(1, 0);
else
{
Type det = 0;
for (size_t i = 0; i < Columns; ++i)
{
const Type cofactor = (i % 2 == 0 ? 1 : -1) * At(0, i) * Minor(0, i).Determinant();
det += cofactor;
}
return det;
}
}
[[nodiscard]]
constexpr Mat<Rows - 1, Columns - 1, Type, StoreType> Minor(const size_t row, const size_t column) const
{
Mat<Rows - 1, Columns - 1, Type, StoreType> result;
for (size_t i = 0, m = 0; i < Rows; ++i)
{
if (i == row)
continue;
for (size_t j = 0, n = 0; j < Columns; ++j)
{
if (j == column)
continue;
result.At(m, n) = At(i, j);
++n;
}
++m;
}
return result;
}
[[nodiscard]]
constexpr const std::array<Type, Rows * Columns>& RawArray() const
{
return m_data;
}
[[nodiscard]]
constexpr std::array<Type, Rows * Columns>& RawArray()
{
return const_cast<std::array<Type, Rows * Columns>>(std::as_const(*this).RawArray());
}
[[nodiscard]]
std::string ToString() const noexcept
{
std::ostringstream oss;
for (size_t i = 0; i < Rows; ++i)
{
for (size_t j = 0; j < Columns; ++j)
{
oss << At(i, j);
if (j != Columns - 1)
oss << ' ';
}
oss << '\n';
}
return oss.str();
}
[[nodiscard]]
bool operator==(const Mat& mat) const
{
return m_data == mat.m_data;
}
[[nodiscard]]
bool operator!=(const Mat& mat) const
{
return !operator==(mat);
}
// Static methods that return fixed-size matrices
[[nodiscard]]
constexpr static Mat<4, 4> ToScreenMat(const Type& screenWidth, const Type& screenHeight) noexcept
{
return {
{screenWidth / 2, 0, 0, 0},
{0, -screenHeight / 2, 0, 0},
{0, 0, 1, 0},
{screenWidth / 2, screenHeight / 2, 0, 1},
};
}
private:
std::array<Type, Rows * Columns> m_data;
};
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3<Type>& vector) noexcept
{
return {{vector.x, vector.y, vector.z, 1}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3<Type>& vector) noexcept
{
return {{vector.x}, {vector.y}, {vector.z}, {1}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3<Type>& diff) noexcept
{
return
{
{1, 0, 0, diff.x},
{0, 1, 0, diff.y},
{0, 0, 1, diff.z},
{0, 0, 0, 1},
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard]]
Mat<4, 4, Type, St> MatRotationAxisX(const Angle& angle) noexcept
{
return
{
{1, 0, 0, 0},
{0, angle.Cos(), -angle.Sin(), 0},
{0, angle.Sin(), angle.Cos(), 0},
{0, 0, 0, 1}
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard]]
Mat<4, 4, Type, St> MatRotationAxisY(const Angle& angle) noexcept
{
return
{
{angle.Cos(), 0, angle.Sin(), 0},
{0 , 1, 0, 0},
{-angle.Sin(), 0, angle.Cos(), 0},
{0 , 0, 0, 1}
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard]]
Mat<4, 4, Type, St> MatRotationAxisZ(const Angle& angle) noexcept
{
return
{
{angle.Cos(), -angle.Sin(), 0, 0},
{angle.Sin(), angle.Cos(), 0, 0},
{ 0, 0, 1, 0},
{ 0, 0, 0, 1},
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
static Mat<4, 4, Type, St> MatCameraView(const Vector3<Type>& forward, const Vector3<Type>& right,
const Vector3<Type>& up, const Vector3<Type>& cameraOrigin) noexcept
{
return Mat<4, 4, Type, St>
{
{right.x, right.y, right.z, 0},
{up.x, up.y, up.z, 0},
{forward.x, forward.y, forward.z, 0},
{0, 0, 0, 1},
} * MatTranslation<Type, St>(-cameraOrigin);
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class ViewAngles>
[[nodiscard]]
Mat<4, 4, Type, St> MatRotation(const ViewAngles& angles) noexcept
{
return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll);
}
} // namespace omath
-74
View File
@@ -1,74 +0,0 @@
//
// Created by Orange on 11/13/2024.
//
#pragma once
#include "omath/Vector3.hpp"
namespace omath
{
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
-203
View File
@@ -1,203 +0,0 @@
//
// Created by Vlad on 02.09.2024.
//
#pragma once
#include <tuple>
#include <cmath>
namespace omath
{
template<class Type> requires std::is_arithmetic_v<Type>
class Vector2
{
public:
Type x = static_cast<Type>(0);
Type y = static_cast<Type>(0);
// Constructors
constexpr Vector2() = default;
constexpr Vector2(const Type& x, const Type& y) : x(x), y(y) {}
// Equality operators
[[nodiscard]]
constexpr bool operator==(const Vector2& src) const
{
return x == src.x && y == src.y;
}
[[nodiscard]]
constexpr bool operator!=(const Vector2& src) const
{
return !(*this == src);
}
// Compound assignment operators
constexpr Vector2& operator+=(const Vector2& v)
{
x += v.x;
y += v.y;
return *this;
}
constexpr Vector2& operator-=(const Vector2& v)
{
x -= v.x;
y -= v.y;
return *this;
}
constexpr Vector2& operator*=(const Vector2& v)
{
x *= v.x;
y *= v.y;
return *this;
}
constexpr Vector2& operator/=(const Vector2& v)
{
x /= v.x;
y /= v.y;
return *this;
}
constexpr Vector2& operator*=(const Type& fl)
{
x *= fl;
y *= fl;
return *this;
}
constexpr Vector2& operator/=(const Type& fl)
{
x /= fl;
y /= fl;
return *this;
}
constexpr Vector2& operator+=(const Type& fl)
{
x += fl;
y += fl;
return *this;
}
constexpr Vector2& operator-=(const Type& fl)
{
x -= fl;
y -= fl;
return *this;
}
// Basic vector operations
[[nodiscard]] Type DistTo(const Vector2& vOther) const
{
return std::sqrt(DistToSqr(vOther));
}
[[nodiscard]] constexpr Type DistToSqr(const Vector2& vOther) const
{
return (x - vOther.x) * (x - vOther.x) + (y - vOther.y) * (y - vOther.y);
}
[[nodiscard]] constexpr Type Dot(const Vector2& vOther) const
{
return x * vOther.x + y * vOther.y;
}
#ifndef _MSC_VER
[[nodiscard]] constexpr Type& Length() const
{
return std::hypot(x, y);
}
[[nodiscard]] constexpr Vector2 Normalized() const
{
const Type len = Length();
return len > 0.f ? *this / len : *this;
}
#else
[[nodiscard]] Type Length() const
{
return std::hypot(x, y);
}
[[nodiscard]] Vector2 Normalized() const
{
const Type len = Length();
return len > 0.f ? *this / len : *this;
}
#endif
[[nodiscard]] constexpr Type LengthSqr() const
{
return x * x + y * y;
}
constexpr Vector2& Abs()
{
//FIXME: Replace with std::abs, if it will become constexprable
x = x < 0 ? -x : x;
y = y < 0 ? -y : y;
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
{
return {-x, -y};
}
// Binary arithmetic operators
[[nodiscard]] constexpr Vector2 operator+(const Vector2& v) const
{
return {x + v.x, y + v.y};
}
[[nodiscard]] constexpr Vector2 operator-(const Vector2& v) const
{
return {x - v.x, y - v.y};
}
[[nodiscard]] constexpr Vector2 operator*(const float fl) const
{
return {x * fl, y * fl};
}
[[nodiscard]] constexpr Vector2 operator/(const float fl) const
{
return {x / fl, y / fl};
}
// Sum of elements
[[nodiscard]] constexpr Type Sum() const
{
return x + y;
}
[[nodiscard]]
constexpr std::tuple<Type, Type> AsTuple() const
{
return std::make_tuple(x, y);
}
};
}
-283
View File
@@ -1,283 +0,0 @@
//
// Created by vlad on 10/28/23.
//
#pragma once
#include <cstdint>
#include <functional>
#include "omath/Vector2.hpp"
#include "omath/Angle.hpp"
#include <expected>
#include <immintrin.h>
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 float DistToSqr(const Vector3& vOther) const
{
return (*this - vOther).LengthSqr();
}
[[nodiscard]] constexpr float Dot(const Vector3& vOther) const
{
return Vector2<Type>::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(this->x, this->y, z);
}
[[nodiscard]] Vector3 Normalized() const
{
const float length = this->Length();
return length != 0 ? *this / length : *this;
}
[[nodiscard]] Type Length2D() const
{
return Vector2<Type>::Length();
}
[[nodiscard]] float DistTo(const Vector3& vOther) const
{
return (*this - vOther).Length();
}
#endif
[[nodiscard]] constexpr float 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 float 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 float Sum2D() const
{
return Vector2<Type>::Sum();
}
[[nodiscard]] constexpr std::tuple<float, float, float> 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;
}
};
}
-158
View File
@@ -1,158 +0,0 @@
//
// Vector4.h
//
#pragma once
#include <omath/Vector3.hpp>
#include <algorithm>
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 float 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 float min, const float 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 float 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 float 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;
}
};
}
@@ -3,8 +3,9 @@
// //
#pragma once #pragma once
#include "omath/Angles.hpp" #include "omath/angles.hpp"
#include <algorithm> #include <algorithm>
#include <utility>
namespace omath namespace omath
{ {
@@ -19,10 +20,10 @@ namespace omath
class Angle class Angle
{ {
Type m_angle; Type m_angle;
constexpr Angle(const Type& degrees) constexpr explicit Angle(const Type& degrees) noexcept
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
m_angle = angles::WrapAngle(degrees, min, max); m_angle = angles::wrap_angle(degrees, min, max);
else if constexpr (flags == AngleFlags::Clamped) else if constexpr (flags == AngleFlags::Clamped)
m_angle = std::clamp(degrees, min, max); m_angle = std::clamp(degrees, min, max);
@@ -32,75 +33,74 @@ namespace omath
std::unreachable(); std::unreachable();
} }
} }
public: public:
[[nodiscard]] [[nodiscard]]
constexpr static Angle FromDegrees(const Type& degrees) constexpr static Angle from_degrees(const Type& degrees) noexcept
{ {
return {degrees}; return Angle{degrees};
} }
constexpr Angle() : m_angle(0) constexpr Angle() noexcept: m_angle(0)
{ {
} }
[[nodiscard]] [[nodiscard]]
constexpr static Angle FromRadians(const Type& degrees) constexpr static Angle from_radians(const Type& degrees) noexcept
{ {
return {angles::RadiansToDegrees<Type>(degrees)}; return Angle{angles::radians_to_degrees<Type>(degrees)};
} }
[[nodiscard]] [[nodiscard]]
constexpr const Type& operator*() const constexpr const Type& operator*() const noexcept
{ {
return m_angle; return m_angle;
} }
[[nodiscard]] [[nodiscard]]
constexpr Type AsDegrees() const constexpr Type as_degrees() const noexcept
{ {
return m_angle; return m_angle;
} }
[[nodiscard]] [[nodiscard]]
constexpr Type AsRadians() const constexpr Type as_radians() const noexcept
{ {
return angles::DegreesToRadians(m_angle); return angles::degrees_to_radians(m_angle);
} }
[[nodiscard]] [[nodiscard]]
Type Sin() const Type sin() const noexcept
{ {
return std::sin(AsRadians()); return std::sin(as_radians());
} }
[[nodiscard]] [[nodiscard]]
Type Cos() const Type cos() const noexcept
{ {
return std::cos(AsRadians()); return std::cos(as_radians());
} }
[[nodiscard]] [[nodiscard]]
Type Tan() const Type tan() const noexcept
{ {
return std::tan(AsRadians()); return std::tan(as_radians());
} }
[[nodiscard]] [[nodiscard]]
Type Atan() const Type atan() const noexcept
{ {
return std::atan(AsRadians()); return std::atan(as_radians());
} }
[[nodiscard]] [[nodiscard]]
Type Cot() const Type cot() const noexcept
{ {
return Cos() / Sin(); return cos() / sin();
} }
[[nodiscard]] constexpr Angle& operator+=(const Angle& other) noexcept
constexpr Angle& operator+=(const Angle& other)
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
m_angle = angles::WrapAngle(m_angle + other.m_angle, min, max); m_angle = angles::wrap_angle(m_angle + other.m_angle, min, max);
else if constexpr (flags == AngleFlags::Clamped) else if constexpr (flags == AngleFlags::Clamped)
m_angle = std::clamp(m_angle + other.m_angle, min, max); m_angle = std::clamp(m_angle + other.m_angle, min, max);
@@ -114,19 +114,18 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
constexpr std::partial_ordering operator<=>(const Angle& other) const = default; constexpr std::partial_ordering operator<=>(const Angle& other) const noexcept = default;
[[nodiscard]] constexpr Angle& operator-=(const Angle& other) noexcept
constexpr Angle& operator-=(const Angle& other)
{ {
return operator+=(-other); return operator+=(-other);
} }
[[nodiscard]] [[nodiscard]]
constexpr Angle& operator+(const Angle& other) constexpr Angle& operator+(const Angle& other) noexcept
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
return {angles::WrapAngle(m_angle + other.m_angle, min, max)}; return {angles::wrap_angle(m_angle + other.m_angle, min, max)};
else if constexpr (flags == AngleFlags::Clamped) else if constexpr (flags == AngleFlags::Clamped)
return {std::clamp(m_angle + other.m_angle, min, max)}; return {std::clamp(m_angle + other.m_angle, min, max)};
@@ -138,15 +137,15 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
constexpr Angle& operator-(const Angle& other) constexpr Angle& operator-(const Angle& other) noexcept
{ {
return operator+(-other); return operator+(-other);
} }
[[nodiscard]] [[nodiscard]]
constexpr Angle operator-() const constexpr Angle operator-() const noexcept
{ {
return {-m_angle}; return Angle{-m_angle};
} }
}; };
} } // namespace omath
+64
View File
@@ -0,0 +1,64 @@
//
// Created by vlad on 11/6/23.
//
#pragma once
#include <cmath>
#include <numbers>
namespace omath::angles
{
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr Type radians_to_degrees(const Type& radians) noexcept
{
return radians * (static_cast<Type>(180) / std::numbers::pi_v<Type>);
}
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] constexpr Type degrees_to_radians(const Type& degrees) noexcept
{
return degrees * (std::numbers::pi_v<Type> / static_cast<Type>(180));
}
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] Type horizontal_fov_to_vertical(const Type& horizontal_fov, const Type& aspect) noexcept
{
const auto fov_rad = degrees_to_radians(horizontal_fov);
const auto vert_fov = static_cast<Type>(2) * std::atan(std::tan(fov_rad / static_cast<Type>(2)) / aspect);
return radians_to_degrees(vert_fov);
}
template<class Type>
requires std::is_floating_point_v<Type>
[[nodiscard]] Type vertical_fov_to_horizontal(const Type& vertical_fov, const Type& aspect) noexcept
{
const auto fov_as_radians = degrees_to_radians(vertical_fov);
const auto horizontal_fov =
static_cast<Type>(2) * std::atan(std::tan(fov_as_radians / static_cast<Type>(2)) * aspect);
return radians_to_degrees(horizontal_fov);
}
template<class Type>
requires std::is_arithmetic_v<Type>
[[nodiscard]] Type wrap_angle(const Type& angle, const Type& min, const Type& max) noexcept
{
if (angle <= max && angle >= min)
return angle;
const Type range = max - min;
Type wrapped_angle = std::fmod(angle - min, range);
if (wrapped_angle < 0)
wrapped_angle += range;
return wrapped_angle + min;
}
} // namespace omath::angles
@@ -3,8 +3,8 @@
// //
#pragma once #pragma once
#include "omath/Vector3.hpp" #include "omath/triangle.hpp"
#include "omath/Triangle.hpp" #include "omath/vector3.hpp"
namespace omath::collision namespace omath::collision
{ {
@@ -13,26 +13,25 @@ namespace omath::collision
public: public:
Vector3<float> start; Vector3<float> start;
Vector3<float> end; Vector3<float> end;
bool infinite_length = false;
[[nodiscard]] [[nodiscard]]
Vector3<float> DirectionVector() const; Vector3<float> direction_vector() const noexcept;
[[nodiscard]] [[nodiscard]]
Vector3<float> DirectionVectorNormalized() const; Vector3<float> direction_vector_normalized() const noexcept;
}; };
class LineTracer class LineTracer
{ {
public: public:
LineTracer() = delete; LineTracer() = delete;
[[nodiscard]] [[nodiscard]]
static bool CanTraceLine(const Ray& ray, const Triangle<Vector3<float>>& triangle); static bool can_trace_line(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept;
// 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<float> GetRayHitPoint(const Ray& ray, const Triangle<Vector3<float>>& triangle); static Vector3<float> get_ray_hit_point(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept;
}; };
} } // namespace omath::collision
+177
View File
@@ -0,0 +1,177 @@
//
// Created by vlad on 2/4/24.
//
#pragma once
#include "omath/vector3.hpp"
#include "omath/vector4.hpp"
#include <cstdint>
#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) noexcept: Vector4(r, g, b, a)
{
clamp(0.f, 1.f);
}
constexpr explicit Color() noexcept = default;
[[nodiscard]]
constexpr static Color from_rgba(const uint8_t r, const uint8_t g, const uint8_t b, const uint8_t a) noexcept
{
return Color{Vector4(r, g, b, a) / 255.f};
}
[[nodiscard]]
constexpr static Color from_hsv(float hue, const float saturation, const float value) noexcept
{
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.f - static_cast<float>(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 from_hsv(const Hsv& hsv) noexcept
{
return from_hsv(hsv.hue, hsv.saturation, hsv.value);
}
[[nodiscard]]
constexpr Hsv to_hsv() const noexcept
{
Hsv hsv_data;
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)
hsv_data.hue = 0.f;
else if (max == red)
hsv_data.hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
else if (max == green)
hsv_data.hue = 60.f * (((blue - red) / delta) + 2.f);
else if (max == blue)
hsv_data.hue = 60.f * (((red - green) / delta) + 4.f);
if (hsv_data.hue < 0.f)
hsv_data.hue += 360.f;
hsv_data.hue /= 360.f;
hsv_data.saturation = max == 0.f ? 0.f : delta / max;
hsv_data.value = max;
return hsv_data;
}
constexpr explicit Color(const Vector4& vec) noexcept: Vector4(vec)
{
clamp(0.f, 1.f);
}
constexpr void set_hue(const float hue) noexcept
{
auto hsv = to_hsv();
hsv.hue = hue;
*this = from_hsv(hsv);
}
constexpr void set_saturation(const float saturation) noexcept
{
auto hsv = to_hsv();
hsv.saturation = saturation;
*this = from_hsv(hsv);
}
constexpr void set_value(const float value) noexcept
{
auto hsv = to_hsv();
hsv.value = value;
*this = from_hsv(hsv);
}
[[nodiscard]]
constexpr Color blend(const Color& other, float ratio) const noexcept
{
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};
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImColor to_im_color() const noexcept
{
return {to_im_vec4()};
}
#endif
};
} // namespace omath
-19
View File
@@ -1,19 +0,0 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include "Constants.hpp"
#include "omath/projection/Camera.hpp"
namespace omath::opengl
{
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;
};
}
@@ -1,25 +0,0 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include <omath/Vector3.hpp>
#include <omath/Mat.hpp>
#include <omath/Angle.hpp>
#include <omath/ViewAngles.hpp>
namespace omath::opengl
{
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, 0.f, 180.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, 0.f, 360.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, 0.f, 360.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
}
-54
View File
@@ -1,54 +0,0 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include "Constants.hpp"
namespace omath::opengl
{
[[nodiscard]]
inline Vector3<float> 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<float> 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<float> 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<float>& cam_origin)
{
return MatCameraView<float, MatStoreType::COLUMN_MAJOR>(-ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
}
[[nodiscard]]
inline 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},
};
}
}
-19
View File
@@ -1,19 +0,0 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include "Constants.hpp"
#include "omath/projection/Camera.hpp"
namespace omath::source
{
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;
};
}
@@ -1,24 +0,0 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include <omath/Vector3.hpp>
#include <omath/Mat.hpp>
#include <omath/Angle.hpp>
#include <omath/ViewAngles.hpp>
namespace omath::source
{
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>;
} // namespace omath::source
-57
View File
@@ -1,57 +0,0 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include "Constants.hpp"
namespace omath::source
{
[[nodiscard]]
inline Vector3<float> 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<float> 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<float> 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<float>& 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
@@ -0,0 +1,22 @@
//
// 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& view_angles, const projection::ViewPort& view_port,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void look_at(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4X4 calc_view_matrix() const noexcept override;
[[nodiscard]] Mat4X4 calc_projection_matrix() const noexcept override;
};
} // namespace omath::iw_engine
@@ -0,0 +1,25 @@
//
// Created by Vlad on 3/17/2025.
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
namespace omath::iw_engine
{
constexpr Vector3<float> k_abs_up = {0, 0, 1};
constexpr Vector3<float> k_abs_right = {0, -1, 0};
constexpr Vector3<float> k_abs_forward = {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>;
} // namespace omath::iw_engine
@@ -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> forward_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
} // namespace omath::iw_engine
@@ -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& view_angles, const projection::ViewPort& view_port,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void look_at(const Vector3<float>& target) override;
[[nodiscard]] Mat4X4 calc_view_matrix() const noexcept override;
[[nodiscard]] Mat4X4 calc_projection_matrix() const noexcept override;
};
} // namespace omath::opengl_engine
@@ -0,0 +1,25 @@
//
// 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> k_abs_up = {0, 1, 0};
constexpr Vector3<float> k_abs_right = {1, 0, 0};
constexpr Vector3<float> k_abs_forward = {0, 0, -1};
using Mat4X4 = Mat<4, 4, float, MatStoreType::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>;
} // namespace omath::opengl_engine
@@ -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> forward_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
} // namespace omath::opengl_engine
@@ -0,0 +1,21 @@
//
// 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& view_angles, const projection::ViewPort& view_port,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void look_at(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4X4 calc_view_matrix() const noexcept override;
[[nodiscard]] Mat4X4 calc_projection_matrix() const noexcept override;
};
} // namespace omath::source_engine
@@ -0,0 +1,25 @@
//
// Created by Orange on 12/4/2024.
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
namespace omath::source_engine
{
constexpr Vector3<float> k_abs_up = {0, 0, 1};
constexpr Vector3<float> k_abs_right = {0, -1, 0};
constexpr Vector3<float> k_abs_forward = {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>;
} // namespace omath::source_engine
@@ -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> forward_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
} // namespace omath::source_engine
@@ -0,0 +1,22 @@
//
// 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& view_angles, const projection::ViewPort& view_port,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, float near, float far);
void look_at(const Vector3<float>& target) override;
protected:
[[nodiscard]] Mat4X4 calc_view_matrix() const noexcept override;
[[nodiscard]] Mat4X4 calc_projection_matrix() const noexcept override;
};
} // namespace omath::unity_engine
@@ -0,0 +1,26 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <omath/view_angles.hpp>
namespace omath::unity_engine
{
constexpr Vector3<float> k_abs_up = {0, 1, 0};
constexpr Vector3<float> k_abs_right = {1, 0, 0};
constexpr Vector3<float> k_abs_forward = {0, 0, 1};
using Mat4X4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3X3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat1X3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
using PitchAngle = Angle<float, -90.f, 90.f, AngleFlags::Clamped>;
using YawAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using RollAngle = Angle<float, -180.f, 180.f, AngleFlags::Normalized>;
using ViewAngles = omath::ViewAngles<PitchAngle, YawAngle, RollAngle>;
} // namespace omath::unity_engine
@@ -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> forward_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept;
[[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept;
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept;
[[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept;
[[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far) noexcept;
} // namespace omath::unity_engine
+482
View File
@@ -0,0 +1,482 @@
//
// Created by vlad on 9/29/2024.
//
#pragma once
#include "omath/vector3.hpp"
#include <algorithm>
#include <array>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <utility>
#ifdef near
#undef near
#endif
#ifdef far
#undef far
#endif
namespace omath
{
struct MatSize
{
size_t rows, columns;
};
enum class MatStoreType : uint8_t
{
ROW_MAJOR = 0,
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>
requires std::is_arithmetic_v<Type>
class Mat final
{
public:
constexpr Mat() noexcept
{
clear();
}
[[nodiscard]]
constexpr static MatStoreType get_store_ordering() noexcept
{
return StoreType;
}
constexpr Mat(const std::initializer_list<std::initializer_list<Type>>& rows)
{
if (rows.size() != Rows)
throw std::invalid_argument("Initializer list rows size does not match template parameter Rows");
auto row_it = rows.begin();
for (size_t i = 0; i < Rows; ++i, ++row_it)
{
if (row_it->size() != Columns)
throw std::invalid_argument(
"All rows must have the same number of columns as template parameter Columns");
auto col_it = row_it->begin();
for (size_t j = 0; j < Columns; ++j, ++col_it)
{
at(i, j) = std::move(*col_it);
}
}
}
constexpr explicit Mat(const Type* raw_data)
{
std::copy_n(raw_data, Rows * Columns, m_data.begin());
}
constexpr Mat(const Mat& other) noexcept
{
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
{
m_data = std::move(other.m_data);
}
[[nodiscard]]
static constexpr size_t row_count() noexcept
{
return Rows;
}
[[nodiscard]]
static constexpr size_t columns_count() noexcept
{
return Columns;
}
[[nodiscard]]
static consteval MatSize size() noexcept
{
return {Rows, Columns};
}
[[nodiscard]]
constexpr const Type& at(const size_t row_index, const size_t column_index) const
{
#if !defined(NDEBUG) && defined(OMATH_SUPRESS_SAFETY_CHECKS)
if (row_index >= Rows || column_index >= Columns)
throw std::out_of_range("Index out of range");
#endif
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return m_data[row_index * Columns + column_index];
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
return m_data[row_index + column_index * Rows];
else
{
static_assert(false, "Invalid matrix access convention");
std::unreachable();
}
}
[[nodiscard]] constexpr Type& at(const size_t row_index, const size_t column_index)
{
return const_cast<Type&>(std::as_const(*this).at(row_index, column_index));
}
[[nodiscard]]
constexpr Type sum() const noexcept
{
return std::accumulate(m_data.begin(), m_data.end(), static_cast<Type>(0));
}
constexpr void clear() noexcept
{
set(static_cast<Type>(0));
}
constexpr void set(const Type& value) noexcept
{
std::ranges::fill(m_data, value);
}
// Operator overloading for multiplication with another Mat
template<size_t OtherColumns> [[nodiscard]]
constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{
Mat<Rows, OtherColumns, Type, StoreType> result;
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < OtherColumns; ++j)
{
Type sum = 0;
for (size_t k = 0; k < Columns; ++k)
sum += at(i, k) * other.at(k, j);
result.at(i, j) = sum;
}
return result;
}
constexpr Mat& operator*=(const Type& f) noexcept
{
std::ranges::for_each(m_data, [&f](auto& val) { val *= f; });
return *this;
}
template<size_t OtherColumns> constexpr Mat<Rows, OtherColumns, Type, StoreType>
operator*=(const Mat<Columns, OtherColumns, Type, StoreType>& other)
{
return *this = *this * other;
}
[[nodiscard]]
constexpr Mat operator*(const Type& value) const noexcept
{
Mat result(*this);
result *= value;
return result;
}
constexpr Mat& operator/=(const Type& value) noexcept
{
std::ranges::for_each(m_data, [&value](auto& val) { val /= value; });
return *this;
}
[[nodiscard]]
constexpr Mat operator/(const Type& value) const noexcept
{
Mat result(*this);
result /= value;
return result;
}
constexpr Mat& operator=(const Mat& other) noexcept
{
if (this != &other)
m_data = other.m_data;
return *this;
}
constexpr Mat& operator=(Mat&& other) noexcept
{
if (this != &other)
m_data = std::move(other.m_data);
return *this;
}
[[nodiscard]]
constexpr Mat<Columns, Rows, Type, StoreType> transposed() const noexcept
{
Mat<Columns, Rows, Type, StoreType> transposed;
for (size_t i = 0; i < Rows; ++i)
for (size_t j = 0; j < Columns; ++j)
transposed.at(j, i) = at(i, j);
return transposed;
}
[[nodiscard]]
constexpr Type determinant() const
{
static_assert(Rows == Columns, "Determinant is only defined for square matrices.");
if constexpr (Rows == 1)
return at(0, 0);
if constexpr (Rows == 2)
return at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0);
if constexpr (Rows > 2)
{
Type det = 0;
for (size_t column = 0; column < Columns; ++column)
{
const Type cofactor = at(0, column) * alg_complement(0, column);
det += cofactor;
}
return det;
}
std::unreachable();
}
[[nodiscard]]
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;
for (size_t i = 0, m = 0; i < Rows; ++i)
{
if (i == row)
continue;
for (size_t j = 0, n = 0; j < Columns; ++j)
{
if (j == column)
continue;
result.at(m, n) = at(i, j);
++n;
}
++m;
}
return result;
}
[[nodiscard]]
constexpr Type minor(const size_t row, const size_t column) const
{
return strip(row, column).determinant();
}
[[nodiscard]]
constexpr Type alg_complement(const size_t row, const size_t column) const
{
const auto minor_value = minor(row, column);
return (row + column + 2) % 2 == 0 ? minor_value : -minor_value;
}
[[nodiscard]]
constexpr const std::array<Type, Rows * Columns>& raw_array() const
{
return m_data;
}
[[nodiscard]]
constexpr std::array<Type, Rows * Columns>& raw_array()
{
return m_data;
}
[[nodiscard]]
std::string to_string() const noexcept
{
std::ostringstream oss;
oss << "[[";
for (size_t i = 0; i < Rows; ++i)
{
if (i > 0)
oss << " [";
for (size_t j = 0; j < Columns; ++j)
{
oss << std::setw(9) << std::fixed << std::setprecision(3) << at(i, j);
if (j != Columns - 1)
oss << ", ";
}
oss << (i == Rows - 1 ? "]]" : "]\n");
}
return oss.str();
}
[[nodiscard]]
bool operator==(const Mat& mat) const
{
return m_data == mat.m_data;
}
[[nodiscard]]
bool operator!=(const Mat& mat) const
{
return !operator==(mat);
}
// Static methods that return fixed-size matrices
[[nodiscard]]
constexpr static Mat<4, 4> to_screen_mat(const Type& screen_width, const Type& screen_height) noexcept
{
return {
{screen_width / 2, 0, 0, 0},
{0, -screen_height / 2, 0, 0},
{0, 0, 1, 0},
{screen_width / 2, screen_height / 2, 0, 1},
};
}
[[nodiscard]]
constexpr std::optional<Mat> inverted() const
{
const auto det = determinant();
if (det == 0)
return std::nullopt;
const auto transposed_mat = 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_mat.alg_complement(row, column);
result /= det;
return {result};
}
private:
std::array<Type, Rows * Columns> m_data;
};
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
constexpr static Mat<1, 4, Type, St> mat_row_from_vector(const Vector3<Type>& vector) noexcept
{
return {{vector.x, vector.y, vector.z, 1}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> [[nodiscard]]
constexpr static Mat<4, 1, Type, St> mat_column_from_vector(const Vector3<Type>& vector) noexcept
{
return {{vector.x}, {vector.y}, {vector.z}, {1}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
constexpr Mat<4, 4, Type, St> mat_translation(const Vector3<Type>& diff) noexcept
{
return
{
{1, 0, 0, diff.x},
{0, 1, 0, diff.y},
{0, 0, 1, diff.z},
{0, 0, 0, 1},
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard]]
Mat<4, 4, Type, St> mat_rotation_axis_x(const Angle& angle) noexcept
{
return
{
{1, 0, 0, 0},
{0, angle.cos(), -angle.sin(), 0},
{0, angle.sin(), angle.cos(), 0},
{0, 0, 0, 1}
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard]]
Mat<4, 4, Type, St> mat_rotation_axis_y(const Angle& angle) noexcept
{
return
{
{angle.cos(), 0, angle.sin(), 0},
{0 , 1, 0, 0},
{-angle.sin(), 0, angle.cos(), 0},
{0 , 0, 0, 1}
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard]]
Mat<4, 4, Type, St> mat_rotation_axis_z(const Angle& angle) noexcept
{
return
{
{angle.cos(), -angle.sin(), 0, 0},
{angle.sin(), angle.cos(), 0, 0},
{ 0, 0, 1, 0},
{ 0, 0, 0, 1},
};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
static Mat<4, 4, Type, St> mat_camera_view(const Vector3<Type>& forward, const Vector3<Type>& right,
const Vector3<Type>& up, const Vector3<Type>& camera_origin) noexcept
{
return Mat<4, 4, Type, St>
{
{right.x, right.y, right.z, 0},
{up.x, up.y, up.z, 0},
{forward.x, forward.y, forward.z, 0},
{0, 0, 0, 1},
} * mat_translation<Type, St>(-camera_origin);
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> mat_perspective_left_handed(const float field_of_view, const float aspect_ratio,
const float near, const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, (far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, 1.f, 0.f}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> mat_perspective_right_handed(const float field_of_view, const float aspect_ratio,
const float near, const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, -(far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
}
} // namespace omath
@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "omath/vector3.hpp"
#include <initializer_list> #include <initializer_list>
#include <memory> #include <memory>
#include <string> #include <string>
#include "Vector3.hpp"
namespace omath namespace omath
{ {
@@ -16,51 +16,51 @@ namespace omath
Matrix(const std::initializer_list<std::initializer_list<float>>& rows); Matrix(const std::initializer_list<std::initializer_list<float>>& rows);
[[nodiscard]] [[nodiscard]]
static Matrix ToScreenMatrix(float screenWidth, float screenHeight); static Matrix to_screen_matrix(float screen_width, float screen_height);
[[nodiscard]] [[nodiscard]]
static Matrix TranslationMatrix(const Vector3<float>& diff); static Matrix translation_matrix(const Vector3<float>& diff);
[[nodiscard]] [[nodiscard]]
static Matrix OrientationMatrix(const Vector3<float>& forward, const Vector3<float>& right, const Vector3<float>& up); static Matrix orientation_matrix(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 projection_matrix(float field_of_view, float aspect_ratio, float near, float far);
Matrix(const Matrix& other); Matrix(const Matrix& other);
Matrix(size_t rows, size_t columns, const float* pRaw); Matrix(size_t rows, size_t columns, const float* raw_data);
Matrix(Matrix&& other) noexcept; Matrix(Matrix&& other) noexcept;
[[nodiscard]] [[nodiscard]]
size_t RowCount() const noexcept; size_t row_count() const noexcept;
[[nodiscard]] [[nodiscard]]
float& operator[](size_t row, size_t column); float& operator[](size_t row, size_t column);
[[nodiscard]] [[nodiscard]]
size_t ColumnsCount() const noexcept; size_t columns_count() const noexcept;
[[nodiscard]] [[nodiscard]]
std::pair<size_t, size_t> Size() const noexcept; std::pair<size_t, size_t> size() const noexcept;
[[nodiscard]] [[nodiscard]]
float& At(size_t iRow, size_t iCol); float& at(size_t row, size_t col);
[[nodiscard]] [[nodiscard]]
float Sum(); float sum();
void SetDataFromRaw(const float* pRawMatrix); void set_data_from_raw(const float* raw_matrix);
[[nodiscard]] [[nodiscard]]
Matrix Transpose() const; Matrix transpose() const;
void Set(float val); void set(float val);
[[nodiscard]] [[nodiscard]]
const float& At(size_t iRow, size_t iCol) const; const float& at(size_t row, size_t col) const;
Matrix operator*(const Matrix& other) const; Matrix operator*(const Matrix& other) const;
@@ -72,22 +72,22 @@ namespace omath
Matrix& operator/=(float f); Matrix& operator/=(float f);
void Clear(); void clear();
[[nodiscard]] [[nodiscard]]
Matrix Strip(size_t row, size_t column) const; Matrix strip(size_t row, size_t column) const;
[[nodiscard]] [[nodiscard]]
float Minor(size_t i, size_t j) const; float minor(size_t i, size_t j) const;
[[nodiscard]] [[nodiscard]]
float AlgComplement(size_t i, size_t j) const; float alg_complement(size_t i, size_t j) const;
[[nodiscard]] [[nodiscard]]
float Determinant() const; float determinant() const;
[[nodiscard]] [[nodiscard]]
const float* Raw() const; const float* raw() const;
Matrix& operator=(const Matrix& other); Matrix& operator=(const Matrix& other);
@@ -96,7 +96,7 @@ namespace omath
Matrix operator/(float f) const; Matrix operator/(float f) const;
[[nodiscard]] [[nodiscard]]
std::string ToString() const; std::string to_string() const;
~Matrix(); ~Matrix();
-30
View File
@@ -1,30 +0,0 @@
//
// Created by Vlad on 28.07.2024.
//
#pragma once
#include <vector>
#include "NavigationMesh.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
@@ -1,38 +0,0 @@
//
// Created by Vlad on 28.07.2024.
//
#pragma once
#include "omath/Vector3.hpp"
#include <expected>
#include <vector>
#include <string>
namespace omath::pathfinding
{
enum Error
{
};
class NavigationMesh final
{
public:
[[nodiscard]]
std::expected<Vector3<float>, std::string> GetClosestVertex(const Vector3<float>& point) const;
[[nodiscard]]
const std::vector<Vector3<float>>& GetNeighbors(const Vector3<float>& vertex) const;
[[nodiscard]]
bool Empty() const;
[[nodiscard]] std::vector<uint8_t> Serialize() const;
void Deserialize(const std::vector<uint8_t>& raw);
std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_verTextMap;
};
}
+30
View File
@@ -0,0 +1,30 @@
//
// Created by Vlad on 28.07.2024.
//
#pragma once
#include "omath/pathfinding/navigation_mesh.hpp"
#include "omath/vector3.hpp"
#include <vector>
namespace omath::pathfinding
{
struct PathNode;
class Astar final
{
public:
[[nodiscard]]
static std::vector<Vector3<float>> find_path(const Vector3<float>& start, const Vector3<float>& end,
const NavigationMesh& nav_mesh) noexcept;
private:
[[nodiscard]]
static std::vector<Vector3<float>>
reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list,
const Vector3<float>& current) noexcept;
[[nodiscard]]
static auto get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
const Vector3<float>& end_vertex) noexcept;
};
} // namespace omath::pathfinding
@@ -0,0 +1,37 @@
//
// Created by Vlad on 28.07.2024.
//
#pragma once
#include "omath/vector3.hpp"
#include <expected>
#include <string>
#include <vector>
namespace omath::pathfinding
{
enum Error
{
};
class NavigationMesh final
{
public:
[[nodiscard]]
std::expected<Vector3<float>, std::string> get_closest_vertex(const Vector3<float>& point) const noexcept;
[[nodiscard]]
const std::vector<Vector3<float>>& get_neighbors(const Vector3<float>& vertex) const noexcept;
[[nodiscard]]
bool empty() const;
[[nodiscard]] std::vector<uint8_t> serialize() const noexcept;
void deserialize(const std::vector<uint8_t>& raw) noexcept;
std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_vertex_map;
};
} // namespace omath::pathfinding
@@ -1,20 +0,0 @@
//
// Created by Vlad on 2/23/2025.
//
#pragma once
#include "Projectile.hpp"
#include "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
@@ -1,26 +0,0 @@
//
// Created by Vlad on 2/23/2025.
//
#pragma once
#include "ProjPredEngine.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
@@ -1,41 +0,0 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include <optional>
#include "omath/Vector3.hpp"
#include "omath/projectile_prediction/ProjPredEngine.hpp"
#include "omath/projectile_prediction/Projectile.hpp"
#include "omath/projectile_prediction/Target.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
@@ -1,21 +0,0 @@
//
// 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{};
};
}
@@ -0,0 +1,19 @@
//
// 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>> maybe_calculate_aim_point(const Projectile& projectile,
const Target& target) const = 0;
virtual ~ProjPredEngine() = default;
};
} // namespace omath::projectile_prediction
@@ -0,0 +1,28 @@
//
// 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>>
maybe_calculate_aim_point(const Projectile& projectile, const Target& target) const override;
ProjPredEngineAvx2(float gravity_constant, float simulation_time_step, float maximum_simulation_time);
~ProjPredEngineAvx2() override = default;
private:
[[nodiscard]] static std::optional<float> calculate_pitch(const Vector3<float>& proj_origin,
const Vector3<float>& target_pos,
float bullet_gravity, float v0, float time) ;
// We use [[maybe_unused]] here since AVX2 is not available for ARM and ARM64 CPU
[[maybe_unused]] const float m_gravity_constant;
[[maybe_unused]] const float m_simulation_time_step;
[[maybe_unused]] const float m_maximum_simulation_time;
};
} // namespace omath::projectile_prediction
@@ -0,0 +1,40 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include "omath/projectile_prediction/proj_pred_engine.hpp"
#include "omath/projectile_prediction/projectile.hpp"
#include "omath/projectile_prediction/target.hpp"
#include "omath/vector3.hpp"
#include <optional>
namespace omath::projectile_prediction
{
class ProjPredEngineLegacy final : public ProjPredEngine
{
public:
explicit ProjPredEngineLegacy(float gravity_constant, float simulation_time_step, float maximum_simulation_time,
float distance_tolerance);
[[nodiscard]]
std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile,
const Target& target) const override;
private:
const float m_gravity_constant;
const float m_simulation_time_step;
const float m_maximum_simulation_time;
const float m_distance_tolerance;
[[nodiscard]]
std::optional<float>
maybe_calculate_projectile_launch_pitch_angle(const Projectile& projectile,
const Vector3<float>& target_position) const noexcept;
[[nodiscard]]
bool is_projectile_reached_target(const Vector3<float>& target_position, const Projectile& projectile,
float pitch, float time) const noexcept;
};
} // namespace omath::projectile_prediction
@@ -0,0 +1,20 @@
//
// Created by Vlad on 6/9/2024.
//
#pragma once
#include "omath/vector3.hpp"
namespace omath::projectile_prediction
{
class Projectile final
{
public:
[[nodiscard]]
Vector3<float> predict_position(float pitch, float yaw, float time, float gravity) const noexcept;
Vector3<float> m_origin;
float m_launch_speed{};
float m_gravity_scale{};
};
} // namespace omath::projectile_prediction
@@ -3,27 +3,26 @@
// //
#pragma once #pragma once
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
namespace omath::projectile_prediction namespace omath::projectile_prediction
{ {
class Target final class Target final
{ {
public: public:
[[nodiscard]] [[nodiscard]]
constexpr Vector3<float> PredictPosition(const float time, const float gravity) const constexpr Vector3<float> predict_position(const float time, const float gravity) const noexcept
{ {
auto predicted = m_origin + m_velocity * time; auto predicted = m_origin + m_velocity * time;
if (m_isAirborne) if (m_is_airborne)
predicted.z -= gravity * std::pow(time, 2.f) * 0.5f; predicted.z -= gravity * (time*time) * 0.5f;
return predicted; return predicted;
} }
Vector3<float> m_origin; Vector3<float> m_origin;
Vector3<float> m_velocity; Vector3<float> m_velocity;
bool m_isAirborne{}; bool m_is_airborne{};
}; };
} } // namespace omath::projectile_prediction
-156
View File
@@ -1,156 +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 = 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)
{
}
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();
}
void SetFieldOfView(const FieldOfView& fov)
{
m_fieldOfView = fov;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
}
void SetNearPlane(const float near)
{
m_nearPlaneDistance = near;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
}
void SetFarPlane(const float far)
{
m_farPlaneDistance = far;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
}
void SetViewAngles(const ViewAnglesType& viewAngles)
{
m_viewAngles = viewAngles;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
}
void SetOrigin(const Vector3<float>& origin)
{
m_origin = origin;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
}
void SetViewPort(const ViewPort& viewPort)
{
m_viewPort = viewPort;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
}
[[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
{
if (!m_viewProjectionMatrix.has_value())
m_viewProjectionMatrix = CalcViewProjectionMatrix();
auto projected = m_viewProjectionMatrix.value() * 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);
const auto screenPositionX = (projected.At(0,0)+1.f) / 2.f * m_viewPort.m_width;
const auto screenPositionY = (-projected.At(1,0)+1) / 2.f * m_viewPort.m_height;
return Vector3{screenPositionX, screenPositionY, 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; });
}
};
} // namespace omath::projection
+175
View File
@@ -0,0 +1,175 @@
//
// Created by Vlad on 27.08.2024.
//
#pragma once
#include "omath/projection/error_codes.hpp"
#include <expected>
#include <omath/angle.hpp>
#include <omath/mat.hpp>
#include <omath/vector3.hpp>
#include <type_traits>
namespace omath::projection
{
class ViewPort final
{
public:
float m_width;
float m_height;
[[nodiscard]] constexpr float aspect_ratio() 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& view_angles, const ViewPort& view_port,
const FieldOfView& fov, const float near, const float far) noexcept
: m_view_port(view_port), m_field_of_view(fov), m_far_plane_distance(far), m_near_plane_distance(near),
m_view_angles(view_angles), m_origin(position)
{
}
protected:
virtual void look_at(const Vector3<float>& target) = 0;
[[nodiscard]] virtual Mat4X4Type calc_view_matrix() const noexcept = 0;
[[nodiscard]] virtual Mat4X4Type calc_projection_matrix() const noexcept = 0;
[[nodiscard]] Mat4X4Type calc_view_projection_matrix() const noexcept
{
return calc_projection_matrix() * calc_view_matrix();
}
public:
[[nodiscard]] const Mat4X4Type& get_view_projection_matrix() const noexcept
{
if (!m_view_projection_matrix.has_value())
m_view_projection_matrix = calc_view_projection_matrix();
return m_view_projection_matrix.value();
}
void set_field_of_view(const FieldOfView& fov) noexcept
{
m_field_of_view = fov;
m_view_projection_matrix = std::nullopt;
}
void set_near_plane(const float near) noexcept
{
m_near_plane_distance = near;
m_view_projection_matrix = std::nullopt;
}
void set_far_plane(const float far) noexcept
{
m_far_plane_distance = far;
m_view_projection_matrix = std::nullopt;
}
void set_view_angles(const ViewAnglesType& view_angles) noexcept
{
m_view_angles = view_angles;
m_view_projection_matrix = std::nullopt;
}
void set_origin(const Vector3<float>& origin) noexcept
{
m_origin = origin;
m_view_projection_matrix = std::nullopt;
}
void set_view_port(const ViewPort& view_port) noexcept
{
m_view_port = view_port;
m_view_projection_matrix = std::nullopt;
}
[[nodiscard]] const FieldOfView& get_field_of_view() const noexcept
{
return m_field_of_view;
}
[[nodiscard]] const float& get_near_plane() const noexcept
{
return m_near_plane_distance;
}
[[nodiscard]] const float& get_far_plane() const noexcept
{
return m_far_plane_distance;
}
[[nodiscard]] const ViewAnglesType& get_view_angles() const noexcept
{
return m_view_angles;
}
[[nodiscard]] const Vector3<float>& get_origin() const noexcept
{
return m_origin;
}
[[nodiscard]] std::expected<Vector3<float>, Error>
world_to_screen(const Vector3<float>& world_position) const noexcept
{
auto normalized_cords = world_to_view_port(world_position);
if (!normalized_cords.has_value())
return std::unexpected{normalized_cords.error()};
return ndc_to_screen_position(*normalized_cords);
}
[[nodiscard]] std::expected<Vector3<float>, Error>
world_to_view_port(const Vector3<float>& world_position) const noexcept
{
auto projected = get_view_projection_matrix()
* mat_column_from_vector<float, Mat4X4Type::get_store_ordering()>(world_position);
if (projected.at(3, 0) == 0.0f)
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
projected /= projected.at(3, 0);
if (is_ndc_out_of_bounds(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_view_port{};
Angle<float, 0.f, 180.f, AngleFlags::Clamped> m_field_of_view;
mutable std::optional<Mat4X4Type> m_view_projection_matrix;
float m_far_plane_distance;
float m_near_plane_distance;
ViewAnglesType m_view_angles;
Vector3<float> m_origin;
private:
template<class Type>
[[nodiscard]] constexpr static bool is_ndc_out_of_bounds(const Type& ndc) noexcept
{
return std::ranges::any_of(ndc.raw_array(), [](const auto& val) { return val < -1 || val > 1; });
}
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
{
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
}
};
} // namespace omath::projection
@@ -5,7 +5,6 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
namespace omath::projection namespace omath::projection
{ {
enum class Error : uint16_t enum class Error : uint16_t
+85
View File
@@ -0,0 +1,85 @@
//
// Created by Orange on 11/13/2024.
//
#pragma once
#include "omath/vector3.hpp"
namespace omath
{
/*
v1
|\
| \
a | \ hypot
| \
v2 ----- v3
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> calculate_normal() const
{
const auto b = side_b_vector();
const auto a = side_a_vector();
return b.cross(a).normalized();
}
[[nodiscard]]
float side_a_length() const
{
return m_vertex1.distance_to(m_vertex2);
}
[[nodiscard]]
float side_b_length() const
{
return m_vertex3.distance_to(m_vertex2);
}
[[nodiscard]]
constexpr Vector3<float> side_a_vector() const
{
return m_vertex1 - m_vertex2;
}
[[nodiscard]]
constexpr float hypot() const
{
return m_vertex1.distance_to(m_vertex3);
}
[[nodiscard]]
constexpr bool is_rectangular() const
{
const auto side_a = side_a_length();
const auto side_b = side_b_length();
const auto hypot_value = hypot();
return std::abs(side_a * side_a + side_b * side_b - hypot_value * hypot_value) <= 0.0001f;
}
[[nodiscard]]
constexpr Vector3<float> side_b_vector() const
{
return m_vertex3 - m_vertex2;
}
[[nodiscard]]
constexpr Vector3<float> mid_point() const
{
return (m_vertex1 + m_vertex2 + m_vertex3) / 3;
}
};
} // namespace omath
+207
View File
@@ -0,0 +1,207 @@
//
// Created by Vlad on 02.09.2024.
//
#pragma once
#include <cmath>
#include <tuple>
#ifdef OMATH_IMGUI_INTEGRATION
#include <imgui.h>
#endif
namespace omath
{
template<class Type>
requires std::is_arithmetic_v<Type>
class Vector2
{
public:
Type x = static_cast<Type>(0);
Type y = static_cast<Type>(0);
// Constructors
constexpr Vector2() = default;
constexpr Vector2(const Type& x, const Type& y) noexcept: x(x), y(y)
{
}
// Equality operators
[[nodiscard]]
constexpr bool operator==(const Vector2& other) const noexcept
{
return x == other.x && y == other.y;
}
[[nodiscard]]
constexpr bool operator!=(const Vector2& other) const noexcept
{
return !(*this == other);
}
// Compound assignment operators
constexpr Vector2& operator+=(const Vector2& other) noexcept
{
x += other.x;
y += other.y;
return *this;
}
constexpr Vector2& operator-=(const Vector2& other) noexcept
{
x -= other.x;
y -= other.y;
return *this;
}
constexpr Vector2& operator*=(const Vector2& other) noexcept
{
x *= other.x;
y *= other.y;
return *this;
}
constexpr Vector2& operator/=(const Vector2& other) noexcept
{
x /= other.x;
y /= other.y;
return *this;
}
constexpr Vector2& operator*=(const Type& value) noexcept
{
x *= value;
y *= value;
return *this;
}
constexpr Vector2& operator/=(const Type& value) noexcept
{
x /= value;
y /= value;
return *this;
}
constexpr Vector2& operator+=(const Type& value) noexcept
{
x += value;
y += value;
return *this;
}
constexpr Vector2& operator-=(const Type& value) noexcept
{
x -= value;
y -= value;
return *this;
}
// Basic vector operations
[[nodiscard]] Type distance_to(const Vector2& other) const noexcept
{
return std::sqrt(distance_to_sqr(other));
}
[[nodiscard]] constexpr Type distance_to_sqr(const Vector2& other) const noexcept
{
return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y);
}
[[nodiscard]] constexpr Type dot(const Vector2& other) const noexcept
{
return x * other.x + y * other.y;
}
#ifndef _MSC_VER
[[nodiscard]] constexpr Type length() const noexcept
{
return std::hypot(this->x, this->y);
}
[[nodiscard]] constexpr Vector2 normalized() const noexcept
{
const Type len = length();
return len > 0.f ? *this / len : *this;
}
#else
[[nodiscard]] Type length() const noexcept
{
return std::hypot(x, y);
}
[[nodiscard]] Vector2 normalized() const noexcept
{
const Type len = length();
return len > 0.f ? *this / len : *this;
}
#endif
[[nodiscard]] constexpr Type length_sqr() const noexcept
{
return x * x + y * y;
}
constexpr Vector2& abs() noexcept
{
// FIXME: Replace with std::abs, if it will become constexprable
x = x < 0 ? -x : x;
y = y < 0 ? -y : y;
return *this;
}
[[nodiscard]] constexpr Vector2 operator-() const noexcept
{
return {-x, -y};
}
// Binary arithmetic operators
[[nodiscard]] constexpr Vector2 operator+(const Vector2& other) const noexcept
{
return {x + other.x, y + other.y};
}
[[nodiscard]] constexpr Vector2 operator-(const Vector2& other) const noexcept
{
return {x - other.x, y - other.y};
}
[[nodiscard]] constexpr Vector2 operator*(const Type& value) const noexcept
{
return {x * value, y * value};
}
[[nodiscard]] constexpr Vector2 operator/(const Type& value) const noexcept
{
return {x / value, y / value};
}
// Sum of elements
[[nodiscard]] constexpr Type sum() const noexcept
{
return x + y;
}
[[nodiscard]]
constexpr std::tuple<Type, Type> as_tuple() const noexcept
{
return std::make_tuple(x, y);
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec2 to_im_vec2() const noexcept
{
return {static_cast<float>(this->x), static_cast<float>(this->y)};
}
#endif
};
} // namespace omath
+275
View File
@@ -0,0 +1,275 @@
//
// Created by vlad on 10/28/23.
//
#pragma once
#include "omath/angle.hpp"
#include "omath/vector2.hpp"
#include <cstdint>
#include <expected>
#include <functional>
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) noexcept: Vector2<Type>(x, y), z(z)
{
}
constexpr Vector3() noexcept: Vector2<Type>() {};
[[nodiscard]] constexpr bool operator==(const Vector3& other) const noexcept
{
return Vector2<Type>::operator==(other) && (other.z == z);
}
[[nodiscard]] constexpr bool operator!=(const Vector3& other) const noexcept
{
return !(*this == other);
}
constexpr Vector3& operator+=(const Vector3& other) noexcept
{
Vector2<Type>::operator+=(other);
z += other.z;
return *this;
}
constexpr Vector3& operator-=(const Vector3& other) noexcept
{
Vector2<Type>::operator-=(other);
z -= other.z;
return *this;
}
constexpr Vector3& operator*=(const Type& value) noexcept
{
Vector2<Type>::operator*=(value);
z *= value;
return *this;
}
constexpr Vector3& operator*=(const Vector3& other) noexcept
{
Vector2<Type>::operator*=(other);
z *= other.z;
return *this;
}
constexpr Vector3& operator/=(const Vector3& other) noexcept
{
Vector2<Type>::operator/=(other);
z /= other.z;
return *this;
}
constexpr Vector3& operator+=(const Type& value) noexcept
{
Vector2<Type>::operator+=(value);
z += value;
return *this;
}
constexpr Vector3& operator/=(const Type& value) noexcept
{
Vector2<Type>::operator/=(value);
z /= value;
return *this;
}
constexpr Vector3& operator-=(const Type& value) noexcept
{
Vector2<Type>::operator-=(value);
z -= value;
return *this;
}
constexpr Vector3& abs() noexcept
{
Vector2<Type>::abs();
z = z < 0.f ? -z : z;
return *this;
}
[[nodiscard]] constexpr Type distance_to_sqr(const Vector3& other) const noexcept
{
return (*this - other).length_sqr();
}
[[nodiscard]] constexpr Type dot(const Vector3& other) const noexcept
{
return Vector2<Type>::dot(other) + z * other.z;
}
#ifndef _MSC_VER
[[nodiscard]] constexpr Type length() const
{
return std::hypot(this->x, this->y, z);
}
[[nodiscard]] constexpr Type length_2d() const
{
return Vector2<Type>::length();
}
[[nodiscard]] Type distance_to(const Vector3& other) const
{
return (*this - other).length();
}
[[nodiscard]] constexpr Vector3 normalized() const
{
const Type length_value = this->length();
return length_value != 0 ? *this / length_value : *this;
}
#else
[[nodiscard]] Type length() const noexcept
{
return std::hypot(this->x, this->y, z);
}
[[nodiscard]] Vector3 normalized() const noexcept
{
const Type len = this->length();
return len != 0 ? *this / len : *this;
}
[[nodiscard]] Type length_2d() const noexcept
{
return Vector2<Type>::length();
}
[[nodiscard]] Type distance_to(const Vector3& vOther) const noexcept
{
return (*this - vOther).length();
}
#endif
[[nodiscard]] constexpr Type length_sqr() const noexcept
{
return Vector2<Type>::length_sqr() + z * z;
}
[[nodiscard]] constexpr Vector3 operator-() const noexcept
{
return {-this->x, -this->y, -z};
}
[[nodiscard]] constexpr Vector3 operator+(const Vector3& other) const noexcept
{
return {this->x + other.x, this->y + other.y, z + other.z};
}
[[nodiscard]] constexpr Vector3 operator-(const Vector3& other) const noexcept
{
return {this->x - other.x, this->y - other.y, z - other.z};
}
[[nodiscard]] constexpr Vector3 operator*(const Type& value) const noexcept
{
return {this->x * value, this->y * value, z * value};
}
[[nodiscard]] constexpr Vector3 operator*(const Vector3& other) const noexcept
{
return {this->x * other.x, this->y * other.y, z * other.z};
}
[[nodiscard]] constexpr Vector3 operator/(const Type& value) const noexcept
{
return {this->x / value, this->y / value, z / value};
}
[[nodiscard]] constexpr Vector3 operator/(const Vector3& other) const noexcept
{
return {this->x / other.x, this->y / other.y, z / other.z};
}
[[nodiscard]] constexpr Vector3 cross(const Vector3& other) const noexcept
{
return {this->y * other.z - z * other.y, z * other.x - this->x * other.z,
this->x * other.y - this->y * other.x};
}
[[nodiscard]] constexpr Type sum() const noexcept
{
return sum_2d() + z;
}
[[nodiscard]] std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
angle_between(const Vector3& other) const noexcept
{
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>::from_radians(std::acos(dot(other) / bottom));
}
[[nodiscard]] bool is_perpendicular(const Vector3& other) const noexcept
{
if (const auto angle = angle_between(other))
return angle->as_degrees() == 90.f;
return false;
}
[[nodiscard]] constexpr Type sum_2d() const noexcept
{
return Vector2<Type>::sum();
}
[[nodiscard]] constexpr std::tuple<Type, Type, Type> as_tuple() const noexcept
{
return std::make_tuple(this->x, this->y, z);
}
[[nodiscard]] Vector3 view_angle_to(const Vector3& other) const noexcept
{
const auto distance = distance_to(other);
const auto delta = other - *this;
return {angles::radians_to_degrees(std::asin(delta.z / distance)),
angles::radians_to_degrees(std::atan2(delta.y, delta.x)), 0};
}
};
} // namespace omath
// 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;
}
};
} // namespace std
+174
View File
@@ -0,0 +1,174 @@
//
// Vector4.h
//
#pragma once
#include <algorithm>
#include <omath/vector3.hpp>
namespace omath
{
template<class Type>
requires std::is_arithmetic_v<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() noexcept : Vector3<Type>(), w(0) {};
[[nodiscard]]
constexpr bool operator==(const Vector4& other) const noexcept
{
return Vector3<Type>::operator==(other) && w == other.w;
}
[[nodiscard]]
constexpr bool operator!=(const Vector4& other) const noexcept
{
return !(*this == other);
}
constexpr Vector4& operator+=(const Vector4& other) noexcept
{
Vector3<Type>::operator+=(other);
w += other.w;
return *this;
}
constexpr Vector4& operator-=(const Vector4& other) noexcept
{
Vector3<Type>::operator-=(other);
w -= other.w;
return *this;
}
constexpr Vector4& operator*=(const Type& value) noexcept
{
Vector3<Type>::operator*=(value);
w *= value;
return *this;
}
constexpr Vector4& operator*=(const Vector4& other) noexcept
{
Vector3<Type>::operator*=(other);
w *= other.w;
return *this;
}
constexpr Vector4& operator/=(const Type& value) noexcept
{
Vector3<Type>::operator/=(value);
w /= value;
return *this;
}
constexpr Vector4& operator/=(const Vector4& other) noexcept
{
Vector3<Type>::operator/=(other);
w /= other.w;
return *this;
}
[[nodiscard]] constexpr Type length_sqr() const noexcept
{
return Vector3<Type>::length_sqr() + w * w;
}
[[nodiscard]] constexpr Type dot(const Vector4& other) const noexcept
{
return Vector3<Type>::dot(other) + w * other.w;
}
[[nodiscard]] Vector3<Type> length() const noexcept
{
return std::sqrt(length_sqr());
}
constexpr Vector4& abs() noexcept
{
Vector3<Type>::abs();
w = w < 0.f ? -w : w;
return *this;
}
constexpr Vector4& clamp(const Type& min, const Type& max) noexcept
{
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 noexcept
{
return {-this->x, -this->y, -this->z, -w};
}
[[nodiscard]]
constexpr Vector4 operator+(const Vector4& other) const noexcept
{
return {this->x + other.x, this->y + other.y, this->z + other.z, w + other.w};
}
[[nodiscard]]
constexpr Vector4 operator-(const Vector4& other) const noexcept
{
return {this->x - other.x, this->y - other.y, this->z - other.z, w - other.w};
}
[[nodiscard]]
constexpr Vector4 operator*(const Type& value) const noexcept
{
return {this->x * value, this->y * value, this->z * value, w * value};
}
[[nodiscard]]
constexpr Vector4 operator*(const Vector4& other) const noexcept
{
return {this->x * other.x, this->y * other.y, this->z * other.z, w * other.w};
}
[[nodiscard]]
constexpr Vector4 operator/(const Type& value) const noexcept
{
return {this->x / value, this->y / value, this->z / value, w / value};
}
[[nodiscard]]
constexpr Vector4 operator/(const Vector4& other) const noexcept
{
return {this->x / other.x, this->y / other.y, this->z / other.z, w / other.w};
}
[[nodiscard]]
constexpr Type sum() const noexcept
{
return Vector3<Type>::sum() + w;
}
#ifdef OMATH_IMGUI_INTEGRATION
[[nodiscard]]
ImVec4 to_im_vec4() const noexcept
{
return {
static_cast<float>(this->x),
static_cast<float>(this->y),
static_cast<float>(this->z),
static_cast<float>(w),
};
}
#endif
};
} // namespace omath
@@ -12,4 +12,4 @@ namespace omath
YawType yaw; YawType yaw;
RollType roll; RollType roll;
}; };
} } // namespace omath
+54
View File
@@ -0,0 +1,54 @@
//
// Created by Vlad on 4/18/2025.
//
#include "omath/3d_primitives/box.hpp"
namespace omath::primitives
{
std::array<Triangle<Vector3<float>>, 12> create_box(const Vector3<float>& top, const Vector3<float>& bottom,
const Vector3<float>& dir_forward,
const Vector3<float>& dir_right, const float ratio) noexcept
{
const auto height = top.distance_to(bottom);
const auto side_size = height / ratio;
// corner layout (03 bottom, 47 top)
std::array<Vector3<float>, 8> p;
p[0] = bottom + (dir_forward + dir_right) * side_size; // frontrightbottom
p[1] = bottom + (dir_forward - dir_right) * side_size; // frontleftbottom
p[2] = bottom + (-dir_forward + dir_right) * side_size; // backrightbottom
p[3] = bottom + (-dir_forward - dir_right) * side_size; // backleftbottom
p[4] = top + (dir_forward + dir_right) * side_size; // frontrighttop
p[5] = top + (dir_forward - dir_right) * side_size; // frontlefttop
p[6] = top + (-dir_forward + dir_right) * side_size; // backrighttop
p[7] = top + (-dir_forward - dir_right) * side_size; // 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;
}
} // namespace omath::primitives
-10
View File
@@ -1,10 +0,0 @@
target_sources(omath PRIVATE
Matrix.cpp
color.cpp
)
add_subdirectory(projectile_prediction)
add_subdirectory(pathfinding)
add_subdirectory(projection)
add_subdirectory(collision)
add_subdirectory(engines)
-3
View File
@@ -1,3 +0,0 @@
target_sources(omath PRIVATE
LineTracer.cpp
)
-62
View File
@@ -1,62 +0,0 @@
//
// Created by Orange on 11/13/2024.
//
#include "omath/collision/LineTracer.hpp"
namespace omath::collision
{
bool LineTracer::CanTraceLine(const Ray& ray, const Triangle<Vector3<float>>& triangle)
{
return GetRayHitPoint(ray, triangle) == ray.end;
}
Vector3<float> Ray::DirectionVector() const
{
return end - start;
}
Vector3<float> Ray::DirectionVectorNormalized() const
{
return DirectionVector().Normalized();
}
Vector3<float> LineTracer::GetRayHitPoint(const Ray& ray, const Triangle<Vector3<float>>& triangle)
{
constexpr float kEpsilon = std::numeric_limits<float>::epsilon();
const auto sideA = triangle.SideAVector();
const auto sideB = triangle.SideBVector();
const auto rayDir = ray.DirectionVector();
const auto p = rayDir.Cross(sideB);
const auto det = sideA.Dot(p);
if (std::abs(det) < kEpsilon)
return ray.end;
const auto invDet = 1.0f / det;
const auto t = ray.start - triangle.m_vertex2;
const auto u = t.Dot(p) * invDet;
if ((u < 0 && std::abs(u) > kEpsilon) || (u > 1 && std::abs(u - 1) > kEpsilon))
return ray.end;
const auto q = t.Cross(sideA);
const auto v = rayDir.Dot(q) * invDet;
if ((v < 0 && std::abs(v) > kEpsilon) || (u + v > 1 && std::abs(u + v - 1) > kEpsilon))
return ray.end;
const auto tHit = sideB.Dot(q) * invDet;
if (tHit <= kEpsilon)
return ray.end;
return ray.start + rayDir * tHit;
}
} // namespace omath::collision
+63
View File
@@ -0,0 +1,63 @@
//
// Created by Orange on 11/13/2024.
//
#include "omath/collision/line_tracer.hpp"
namespace omath::collision
{
bool LineTracer::can_trace_line(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept
{
return get_ray_hit_point(ray, triangle) == ray.end;
}
Vector3<float> Ray::direction_vector() const noexcept
{
return end - start;
}
Vector3<float> Ray::direction_vector_normalized() const noexcept
{
return direction_vector().normalized();
}
Vector3<float> LineTracer::get_ray_hit_point(const Ray& ray, const Triangle<Vector3<float>>& triangle) noexcept
{
constexpr float k_epsilon = std::numeric_limits<float>::epsilon();
const auto side_a = triangle.side_a_vector();
const auto side_b = triangle.side_b_vector();
const auto ray_dir = ray.direction_vector();
const auto p = ray_dir.cross(side_b);
const auto det = side_a.dot(p);
if (std::abs(det) < k_epsilon)
return ray.end;
const auto inv_det = 1.0f / det;
const auto t = ray.start - triangle.m_vertex2;
const auto u = t.dot(p) * inv_det;
if ((u < 0 && std::abs(u) > k_epsilon) || (u > 1 && std::abs(u - 1) > k_epsilon))
return ray.end;
const auto q = t.cross(side_a);
// ReSharper disable once CppTooWideScopeInitStatement
const auto v = ray_dir.dot(q) * inv_det;
if ((v < 0 && std::abs(v) > k_epsilon) || (u + v > 1 && std::abs(u + v - 1) > k_epsilon))
return ray.end;
const auto t_hit = side_b.dot(q) * inv_det;
if (ray.infinite_length)
{
if (t_hit <= k_epsilon)
return ray.end;
}
else if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
return ray.end;
return ray.start + ray_dir * t_hit;
}
} // namespace omath::collision
-13
View File
@@ -1,13 +0,0 @@
//
// Created by vlad on 2/4/24.
//
#include "omath/Color.hpp"
#include <algorithm>
#include <cmath>
namespace omath
{
}
-2
View File
@@ -1,2 +0,0 @@
add_subdirectory(Source)
add_subdirectory(OpenGL)
-1
View File
@@ -1 +0,0 @@
target_sources(omath PRIVATE Camera.cpp)
-35
View File
@@ -1,35 +0,0 @@
//
// Created by Orange on 12/23/2024.
//
#include "omath/engines/OpenGL/Camera.hpp"
#include "omath/engines/OpenGL/Formulas.hpp"
namespace omath::opengl
{
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::CalcViewMatrix(m_viewAngles, m_origin);
}
Mat4x4 Camera::CalcProjectionMatrix() const
{
return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance,
m_farPlaneDistance);
}
} // namespace omath::opengl
-1
View File
@@ -1 +0,0 @@
target_sources(omath PRIVATE Camera.cpp)
-37
View File
@@ -1,37 +0,0 @@
//
// Created by Orange on 12/4/2024.
//
#include "omath/engines/Source/Camera.hpp"
#include "omath/engines/Source/Formulas.hpp"
namespace omath::source
{
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(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 source::CalcViewMatrix(m_viewAngles, m_origin);
}
Mat4x4 Camera::CalcProjectionMatrix() const
{
return CalcPerspectiveProjectionMatrix(m_fieldOfView.AsDegrees(), m_viewPort.AspectRatio(), m_nearPlaneDistance,
m_farPlaneDistance);
}
} // namespace omath::source
+33
View File
@@ -0,0 +1,33 @@
//
// 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& view_angles, const projection::ViewPort& view_port,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far)
: projection::Camera<Mat4X4, ViewAngles>(position, view_angles, view_port, fov, near, far)
{
}
void Camera::look_at([[maybe_unused]] const Vector3<float>& target)
{
const float distance = m_origin.distance_to(target);
const auto delta = target - m_origin;
m_view_angles.pitch = PitchAngle::from_radians(std::asin(delta.z / distance));
m_view_angles.yaw = -YawAngle::from_radians(std::atan2(delta.y, delta.x));
m_view_angles.roll = RollAngle::from_radians(0.f);
}
Mat4X4 Camera::calc_view_matrix() const noexcept
{
return iw_engine::calc_view_matrix(m_view_angles, m_origin);
}
Mat4X4 Camera::calc_projection_matrix() const noexcept
{
return calc_perspective_projection_matrix(m_field_of_view.as_degrees(), m_view_port.aspect_ratio(),
m_near_plane_distance, m_far_plane_distance);
}
} // namespace omath::iw_engine
+53
View File
@@ -0,0 +1,53 @@
//
// Created by Vlad on 3/19/2025.
//
#include "omath/engines/iw_engine/formulas.hpp"
namespace omath::iw_engine
{
Vector3<float> forward_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> right_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> up_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_z(angles.yaw) * mat_rotation_axis_y(angles.pitch) * mat_rotation_axis_x(angles.roll);
}
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view(forward_vector(angles), right_vector(angles), up_vector(angles), cam_origin);
}
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept
{
// NOTE: Need magic number to fix fov calculation, since IW engine inherit Quake proj matrix calculation
constexpr auto k_multiply_factor = 0.75f;
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f) * k_multiply_factor;
return {
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
{0, 1.f / (fov_half_tan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1, 0},
};
};
} // namespace omath::iw_engine
+33
View File
@@ -0,0 +1,33 @@
//
// 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& view_angles, const projection::ViewPort& view_port,
const Angle<float, 0.f, 180.f, AngleFlags::Clamped>& fov, const float near, const float far)
: projection::Camera<Mat4X4, ViewAngles>(position, view_angles, view_port, fov, near, far)
{
}
void Camera::look_at([[maybe_unused]] const Vector3<float>& target)
{
const float distance = m_origin.distance_to(target);
const auto delta = target - m_origin;
m_view_angles.pitch = PitchAngle::from_radians(std::asin(delta.z / distance));
m_view_angles.yaw = -YawAngle::from_radians(std::atan2(delta.y, delta.x));
m_view_angles.roll = RollAngle::from_radians(0.f);
}
Mat4X4 Camera::calc_view_matrix() const noexcept
{
return opengl_engine::calc_view_matrix(m_view_angles, m_origin);
}
Mat4X4 Camera::calc_projection_matrix() const noexcept
{
return calc_perspective_projection_matrix(m_field_of_view.as_degrees(), m_view_port.aspect_ratio(),
m_near_plane_distance, m_far_plane_distance);
}
} // namespace omath::opengl_engine
+52
View File
@@ -0,0 +1,52 @@
//
// Created by Vlad on 3/19/2025.
//
#include "omath/engines/opengl_engine/formulas.hpp"
namespace omath::opengl_engine
{
Vector3<float> forward_vector(const ViewAngles& angles) noexcept
{
const auto vec
= rotation_matrix(angles) * mat_column_from_vector<float, MatStoreType::COLUMN_MAJOR>(k_abs_forward);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> right_vector(const ViewAngles& angles) noexcept
{
const auto vec
= rotation_matrix(angles) * mat_column_from_vector<float, MatStoreType::COLUMN_MAJOR>(k_abs_right);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> up_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector<float, MatStoreType::COLUMN_MAJOR>(k_abs_up);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view<float, MatStoreType::COLUMN_MAJOR>(-forward_vector(angles), right_vector(angles),
up_vector(angles), cam_origin);
}
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_x<float, MatStoreType::COLUMN_MAJOR>(-angles.pitch)
* mat_rotation_axis_y<float, MatStoreType::COLUMN_MAJOR>(-angles.yaw)
* mat_rotation_axis_z<float, MatStoreType::COLUMN_MAJOR>(angles.roll);
}
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
{0, 1.f / (fov_half_tan), 0, 0},
{0, 0, -(far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, -1, 0},
};
}
} // namespace omath::opengl_engine
+35
View File
@@ -0,0 +1,35 @@
//
// Created by Orange on 12/4/2024.
//
#include "omath/engines/source_engine/camera.hpp"
#include "omath/engines/source_engine/formulas.hpp"
namespace omath::source_engine
{
Camera::Camera(const Vector3<float>& position, const ViewAngles& view_angles, const projection::ViewPort& view_port,
const projection::FieldOfView& fov, const float near, const float far)
: projection::Camera<Mat4X4, ViewAngles>(position, view_angles, view_port, fov, near, far)
{
}
void Camera::look_at(const Vector3<float>& target)
{
const float distance = m_origin.distance_to(target);
const auto delta = target - m_origin;
m_view_angles.pitch = PitchAngle::from_radians(std::asin(delta.z / distance));
m_view_angles.yaw = -YawAngle::from_radians(std::atan2(delta.y, delta.x));
m_view_angles.roll = RollAngle::from_radians(0.f);
}
Mat4X4 Camera::calc_view_matrix() const noexcept
{
return source_engine::calc_view_matrix(m_view_angles, m_origin);
}
Mat4X4 Camera::calc_projection_matrix() const noexcept
{
return calc_perspective_projection_matrix(m_field_of_view.as_degrees(), m_view_port.aspect_ratio(),
m_near_plane_distance, m_far_plane_distance);
}
} // namespace omath::source_engine
+53
View File
@@ -0,0 +1,53 @@
//
// Created by Vlad on 3/19/2025.
//
#include <omath/engines/source_engine/formulas.hpp>
namespace omath::source_engine
{
Vector3<float> forward_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_z(angles.yaw) * mat_rotation_axis_y(angles.pitch) * mat_rotation_axis_x(angles.roll);
}
Vector3<float> right_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> up_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view(forward_vector(angles), right_vector(angles), up_vector(angles), cam_origin);
}
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept
{
// NOTE: Need magic number to fix fov calculation, since source inherit Quake proj matrix calculation
constexpr auto k_multiply_factor = 0.75f;
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f) * k_multiply_factor;
return {
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
{0, 1.f / (fov_half_tan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1, 0},
};
}
} // namespace omath::source_engine
+27
View File
@@ -0,0 +1,27 @@
//
// 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& view_angles, const projection::ViewPort& view_port,
const projection::FieldOfView& fov, const float near, const float far)
: projection::Camera<Mat4X4, ViewAngles>(position, view_angles, view_port, fov, near, far)
{
}
void Camera::look_at([[maybe_unused]] const Vector3<float>& target)
{
throw std::runtime_error("Not implemented");
}
Mat4X4 Camera::calc_view_matrix() const noexcept
{
return unity_engine::calc_view_matrix(m_view_angles, m_origin);
}
Mat4X4 Camera::calc_projection_matrix() const noexcept
{
return calc_perspective_projection_matrix(m_field_of_view.as_degrees(), m_view_port.aspect_ratio(),
m_near_plane_distance, m_far_plane_distance);
}
} // namespace omath::unity_engine
+49
View File
@@ -0,0 +1,49 @@
//
// Created by Vlad on 3/22/2025.
//
#include "omath/engines/unity_engine/formulas.hpp"
namespace omath::unity_engine
{
Vector3<float> forward_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> right_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> up_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), -right_vector(angles),
up_vector(angles), cam_origin);
}
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch)
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.yaw)
* mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.roll);
}
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far) noexcept
{
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {
{1.f / (aspect_ratio * fov_half_tan), 0, 0, 0},
{0, 1.f / (fov_half_tan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, -1.f, 0},
};
}
} // namespace omath::unity_engine
+70 -74
View File
@@ -1,14 +1,11 @@
#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>
#include <format> #include <format>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
namespace omath namespace omath
{ {
Matrix::Matrix(const size_t rows, const size_t columns) Matrix::Matrix(const size_t rows, const size_t columns)
@@ -21,7 +18,7 @@ namespace omath
m_data = std::make_unique<float[]>(m_rows * m_columns); m_data = std::make_unique<float[]>(m_rows * m_columns);
Set(0.f); set(0.f);
} }
Matrix::Matrix(const std::initializer_list<std::initializer_list<float>>& rows) Matrix::Matrix(const std::initializer_list<std::initializer_list<float>>& rows)
@@ -29,7 +26,6 @@ namespace omath
m_rows = rows.size(); m_rows = rows.size();
m_columns = rows.begin()->size(); m_columns = rows.begin()->size();
for (const auto& row: rows) for (const auto& row: rows)
if (row.size() != m_columns) if (row.size() != m_columns)
throw std::invalid_argument("All rows must have the same number of columns."); throw std::invalid_argument("All rows must have the same number of columns.");
@@ -41,7 +37,7 @@ namespace omath
{ {
size_t j = 0; size_t j = 0;
for (const auto& value: row) for (const auto& value: row)
At(i, j++) = value; at(i, j++) = value;
++i; ++i;
} }
} }
@@ -55,29 +51,28 @@ namespace omath
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
At(i, j) = other.At(i, j); at(i, j) = other.at(i, j);
} }
Matrix::Matrix(const size_t rows, const size_t columns, const float* pRaw) Matrix::Matrix(const size_t rows, const size_t columns, const float* raw_data)
{ {
m_rows = rows; m_rows = rows;
m_columns = columns; m_columns = columns;
m_data = std::make_unique<float[]>(m_rows * m_columns); m_data = std::make_unique<float[]>(m_rows * m_columns);
for (size_t i = 0; i < rows * columns; ++i) for (size_t i = 0; i < rows * columns; ++i)
At(i / rows, i % columns) = pRaw[i]; at(i / rows, i % columns) = raw_data[i];
} }
size_t Matrix::RowCount() const noexcept size_t Matrix::row_count() const noexcept
{ {
return m_rows; return m_rows;
} }
float& Matrix::operator[](const size_t row, const size_t column) float& Matrix::operator[](const size_t row, const size_t column)
{ {
return At(row, column); return at(row, column);
} }
Matrix::Matrix(Matrix&& other) noexcept Matrix::Matrix(Matrix&& other) noexcept
@@ -92,35 +87,35 @@ namespace omath
other.m_data = nullptr; other.m_data = nullptr;
} }
size_t Matrix::ColumnsCount() const noexcept size_t Matrix::columns_count() const noexcept
{ {
return m_columns; return m_columns;
} }
std::pair<size_t, size_t> Matrix::Size() const noexcept std::pair<size_t, size_t> Matrix::size() const noexcept
{ {
return {RowCount(), ColumnsCount()}; return {row_count(), columns_count()};
} }
float& Matrix::At(const size_t iRow, const size_t iCol) float& Matrix::at(const size_t row, const size_t col)
{ {
return const_cast<float&>(std::as_const(*this).At(iRow, iCol)); return const_cast<float&>(std::as_const(*this).at(row, col));
} }
float Matrix::Sum() float Matrix::sum()
{ {
float sum = 0; float sum = 0;
for (size_t i = 0; i < RowCount(); i++) for (size_t i = 0; i < row_count(); i++)
for (size_t j = 0; j < ColumnsCount(); j++) for (size_t j = 0; j < columns_count(); j++)
sum += At(i, j); sum += at(i, j);
return sum; return sum;
} }
const float& Matrix::At(const size_t iRow, const size_t iCol) const const float& Matrix::at(const size_t row, const size_t col) const
{ {
return m_data[iRow * m_columns + iCol]; return m_data[row * m_columns + col];
} }
Matrix Matrix::operator*(const Matrix& other) const Matrix Matrix::operator*(const Matrix& other) const
@@ -128,15 +123,14 @@ namespace omath
if (m_columns != other.m_rows) if (m_columns != other.m_rows)
throw std::runtime_error("n != m"); throw std::runtime_error("n != m");
auto outMat = Matrix(m_rows, other.m_columns); auto out_mat = Matrix(m_rows, other.m_columns);
for (size_t d = 0; d < m_rows; ++d) for (size_t d = 0; d < m_rows; ++d)
for (size_t i = 0; i < other.m_columns; ++i) for (size_t i = 0; i < other.m_columns; ++i)
for (size_t j = 0; j < other.m_rows; ++j) for (size_t j = 0; j < other.m_rows; ++j)
outMat.At(d, i) += At(d, j) * other.At(j, i); out_mat.at(d, i) += at(d, j) * other.at(j, i);
return out_mat;
return outMat;
} }
Matrix& Matrix::operator*=(const Matrix& other) Matrix& Matrix::operator*=(const Matrix& other)
@@ -150,22 +144,22 @@ namespace omath
auto out = *this; auto out = *this;
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
out.At(i, j) *= f; out.at(i, j) *= f;
return out; return out;
} }
Matrix& Matrix::operator*=(const float f) Matrix& Matrix::operator*=(const float f)
{ {
for (size_t i = 0; i < RowCount(); i++) for (size_t i = 0; i < row_count(); i++)
for (size_t j = 0; j < ColumnsCount(); j++) for (size_t j = 0; j < columns_count(); j++)
At(i, j) *= f; at(i, j) *= f;
return *this; return *this;
} }
void Matrix::Clear() void Matrix::clear()
{ {
Set(0.f); set(0.f);
} }
Matrix& Matrix::operator=(const Matrix& other) Matrix& Matrix::operator=(const Matrix& other)
@@ -175,7 +169,7 @@ namespace omath
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
At(i, j) = other.At(i, j); at(i, j) = other.at(i, j);
return *this; return *this;
} }
@@ -199,7 +193,7 @@ namespace omath
{ {
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
At(i, j) /= f; at(i, j) /= f;
return *this; return *this;
} }
@@ -209,12 +203,12 @@ namespace omath
auto out = *this; auto out = *this;
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
out.At(i, j) /= f; out.at(i, j) /= f;
return out; return out;
} }
std::string Matrix::ToString() const std::string Matrix::to_string() const
{ {
std::string str; std::string str;
@@ -222,7 +216,7 @@ namespace omath
{ {
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
{ {
str += std::format("{:.1f}", At(i, j)); str += std::format("{:.1f}", at(i, j));
if (j == m_columns - 1) if (j == m_columns - 1)
str += '\n'; str += '\n';
@@ -233,89 +227,89 @@ namespace omath
return str; return str;
} }
float Matrix::Determinant() const float Matrix::determinant() const // NOLINT(*-no-recursion)
{ {
if (m_rows + m_columns == 2) if (m_rows + m_columns == 2)
return At(0, 0); return at(0, 0);
if (m_rows == 2 and m_columns == 2) if (m_rows == 2 and m_columns == 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);
float fDet = 0; float det = 0;
for (size_t i = 0; i < m_columns; i++) for (size_t i = 0; i < m_columns; i++)
fDet += AlgComplement(0, i) * At(0, i); det += alg_complement(0, i) * at(0, i);
return fDet; return det;
} }
float Matrix::AlgComplement(const size_t i, const size_t j) const float Matrix::alg_complement(const size_t i, const size_t j) const // NOLINT(*-no-recursion)
{ {
const auto tmp = Minor(i, j); const auto tmp = minor(i, j);
return ((i + j + 2) % 2 == 0) ? tmp : -tmp; return ((i + j + 2) % 2 == 0) ? tmp : -tmp;
} }
Matrix Matrix::Transpose() const Matrix Matrix::transpose() const
{ {
Matrix transposed = {m_columns, m_rows}; Matrix transposed = {m_columns, m_rows};
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
transposed.At(j, i) = At(i, j); transposed.at(j, i) = at(i, j);
return transposed; return transposed;
} }
Matrix::~Matrix() = default; Matrix::~Matrix() = default;
void Matrix::Set(const float val) void Matrix::set(const float val)
{ {
for (size_t i = 0; i < m_rows; ++i) for (size_t i = 0; i < m_rows; ++i)
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
At(i, j) = val; at(i, j) = val;
} }
Matrix Matrix::Strip(const size_t row, const size_t column) const Matrix Matrix::strip(const size_t row, const size_t column) const
{ {
Matrix stripped = {m_rows - 1, m_columns - 1}; Matrix stripped = {m_rows - 1, m_columns - 1};
size_t iStripRowIndex = 0; size_t strip_row_index = 0;
for (size_t i = 0; i < m_rows; i++) for (size_t i = 0; i < m_rows; i++)
{ {
if (i == row) if (i == row)
continue; continue;
size_t iStripColumnIndex = 0; size_t strip_column_index = 0;
for (size_t j = 0; j < m_columns; ++j) for (size_t j = 0; j < m_columns; ++j)
{ {
if (j == column) if (j == column)
continue; continue;
stripped.At(iStripRowIndex, iStripColumnIndex) = At(i, j); stripped.at(strip_row_index, strip_column_index) = at(i, j);
iStripColumnIndex++; strip_column_index++;
} }
iStripRowIndex++; strip_row_index++;
} }
return stripped; return stripped;
} }
float Matrix::Minor(const size_t i, const size_t j) const float Matrix::minor(const size_t i, const size_t j) const // NOLINT(*-no-recursion)
{ {
return Strip(i, j).Determinant(); return strip(i, j).determinant();
} }
Matrix Matrix::ToScreenMatrix(const float screenWidth, const float screenHeight) Matrix Matrix::to_screen_matrix(const float screen_width, const float screen_height)
{ {
return { return {
{screenWidth / 2.f, 0.f, 0.f, 0.f}, {screen_width / 2.f, 0.f, 0.f, 0.f},
{0.f, -screenHeight / 2.f, 0.f, 0.f}, {0.f, -screen_height / 2.f, 0.f, 0.f},
{0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 1.f, 0.f},
{screenWidth / 2.f, screenHeight / 2.f, 0.f, 1.f}, {screen_width / 2.f, screen_height / 2.f, 0.f, 1.f},
}; };
} }
Matrix Matrix::TranslationMatrix(const Vector3<float>& diff) Matrix Matrix::translation_matrix(const Vector3<float>& diff)
{ {
return { return {
{1.f, 0.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f},
@@ -325,7 +319,8 @@ namespace omath
}; };
} }
Matrix Matrix::OrientationMatrix(const Vector3<float>& forward, const Vector3<float>& right, const Vector3<float>& up) Matrix Matrix::orientation_matrix(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},
@@ -335,25 +330,26 @@ namespace omath
}; };
} }
Matrix Matrix::ProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near, const float far) Matrix Matrix::projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far)
{ {
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f); const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
return {{1.f / (aspectRatio * fovHalfTan), 0.f, 0.f, 0.f}, return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
{0.f, 1.f / fovHalfTan, 0.f, 0.f}, {0.f, 1.f / fov_half_tan, 0.f, 0.f},
{0.f, 0.f, (far + near) / (far - near), 2.f * near * far / (far - near)}, {0.f, 0.f, (far + near) / (far - near), 2.f * near * far / (far - near)},
{0.f, 0.f, -1.f, 0.f}}; {0.f, 0.f, -1.f, 0.f}};
} }
const float* Matrix::Raw() const const float* Matrix::raw() const
{ {
return m_data.get(); return m_data.get();
} }
void Matrix::SetDataFromRaw(const float* pRawMatrix) void Matrix::set_data_from_raw(const float* raw_matrix)
{ {
for (size_t i = 0; i < m_columns * m_rows; ++i) for (size_t i = 0; i < m_columns * m_rows; ++i)
At(i / m_rows, i % m_columns) = pRawMatrix[i]; at(i / m_rows, i % m_columns) = raw_matrix[i];
} }
Matrix::Matrix() Matrix::Matrix()
-100
View File
@@ -1,100 +0,0 @@
//
// Created by Vlad on 28.07.2024.
//
#include "omath/pathfinding/Astar.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
-1
View File
@@ -1 +0,0 @@
target_sources(omath PRIVATE NavigationMesh.cpp Astar.cpp)
-95
View File
@@ -1,95 +0,0 @@
//
// Created by Vlad on 28.07.2024.
//
#include "omath/pathfinding/NavigationMesh.hpp"
#include <stdexcept>
#include <algorithm>
namespace omath::pathfinding
{
std::expected<Vector3<float>, std::string> NavigationMesh::GetClosestVertex(const Vector3<float> &point) const
{
const auto res = std::ranges::min_element(m_verTextMap,
[&point](const auto& a, const auto& b)
{
return a.first.DistTo(point) < b.first.DistTo(point);
});
if (res == m_verTextMap.cend())
return std::unexpected("Failed to get clossest point");
return res->first;
}
const std::vector<Vector3<float>>& NavigationMesh::GetNeighbors(const Vector3<float> &vertex) const
{
return m_verTextMap.at(vertex);
}
bool NavigationMesh::Empty() const
{
return m_verTextMap.empty();
}
std::vector<uint8_t> NavigationMesh::Serialize() const
{
auto dumpToVector =[]<typename T>(const T& t, std::vector<uint8_t>& vec){
for (size_t i = 0; i < sizeof(t); i++)
vec.push_back(*(reinterpret_cast<const uint8_t*>(&t)+i));
};
std::vector<uint8_t> raw;
for (const auto& [vertex, neighbors] : m_verTextMap)
{
const auto neighborsCount = neighbors.size();
dumpToVector(vertex, raw);
dumpToVector(neighborsCount, raw);
for (const auto& neighbor : neighbors)
dumpToVector(neighbor, raw);
}
return raw;
}
void NavigationMesh::Deserialize(const std::vector<uint8_t> &raw)
{
auto loadFromVector = [](const std::vector<uint8_t>& vec, size_t& offset, auto& value)
{
if (offset + sizeof(value) > vec.size())
{
throw std::runtime_error("Deserialize: Invalid input data size.");
}
std::copy_n(vec.data() + offset, sizeof(value), (uint8_t*)&value);
offset += sizeof(value);
};
m_verTextMap.clear();
size_t offset = 0;
while (offset < raw.size())
{
Vector3<float> vertex;
loadFromVector(raw, offset, vertex);
uint16_t neighborsCount;
loadFromVector(raw, offset, neighborsCount);
std::vector<Vector3<float>> neighbors;
neighbors.reserve(neighborsCount);
for (size_t i = 0; i < neighborsCount; ++i)
{
Vector3<float> neighbor;
loadFromVector(raw, offset, neighbor);
neighbors.push_back(neighbor);
}
m_verTextMap.emplace(vertex, std::move(neighbors));
}
}
}
+99
View File
@@ -0,0 +1,99 @@
//
// 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>> came_from;
float g_cost = 0.f;
};
std::vector<Vector3<float>>
Astar::reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list,
const Vector3<float>& current) noexcept
{
std::vector<Vector3<float>> path;
std::optional current_opt = current;
while (current_opt)
{
path.push_back(*current_opt);
auto it = closed_list.find(*current_opt);
if (it == closed_list.end())
break;
current_opt = it->second.came_from;
}
std::ranges::reverse(path);
return path;
}
auto Astar::get_perfect_node(const std::unordered_map<Vector3<float>, PathNode>& open_list,
const Vector3<float>& end_vertex) noexcept
{
return std::ranges::min_element(open_list,
[&end_vertex](const auto& a, const auto& b)
{
const float fa = a.second.g_cost + a.first.distance_to(end_vertex);
const float fb = b.second.g_cost + b.first.distance_to(end_vertex);
return fa < fb;
});
}
std::vector<Vector3<float>> Astar::find_path(const Vector3<float>& start, const Vector3<float>& end,
const NavigationMesh& nav_mesh) noexcept
{
std::unordered_map<Vector3<float>, PathNode> closed_list;
std::unordered_map<Vector3<float>, PathNode> open_list;
auto maybe_start_vertex = nav_mesh.get_closest_vertex(start);
auto maybe_end_vertex = nav_mesh.get_closest_vertex(end);
if (!maybe_start_vertex || !maybe_end_vertex)
return {};
const auto start_vertex = maybe_start_vertex.value();
const auto end_vertex = maybe_end_vertex.value();
open_list.emplace(start_vertex, PathNode{std::nullopt, 0.f});
while (!open_list.empty())
{
auto current_it = get_perfect_node(open_list, end_vertex);
const auto current = current_it->first;
const auto current_node = current_it->second;
if (current == end_vertex)
return reconstruct_final_path(closed_list, current);
closed_list.emplace(current, current_node);
open_list.erase(current_it);
for (const auto& neighbor: nav_mesh.get_neighbors(current))
{
if (closed_list.contains(neighbor))
continue;
const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current);
// ReSharper disable once CppTooWideScopeInitStatement
const auto open_it = open_list.find(neighbor);
if (open_it == open_list.end() || tentative_g_cost < open_it->second.g_cost)
open_list[neighbor] = PathNode{current, tentative_g_cost};
}
}
return {};
}
} // namespace omath::pathfinding
+91
View File
@@ -0,0 +1,91 @@
//
// Created by Vlad on 28.07.2024.
//
#include "omath/pathfinding/navigation_mesh.hpp"
#include <algorithm>
#include <stdexcept>
namespace omath::pathfinding
{
std::expected<Vector3<float>, std::string>
NavigationMesh::get_closest_vertex(const Vector3<float>& point) const noexcept
{
const auto res = std::ranges::min_element(m_vertex_map, [&point](const auto& a, const auto& b)
{ return a.first.distance_to(point) < b.first.distance_to(point); });
if (res == m_vertex_map.cend())
return std::unexpected("Failed to get clossest point");
return res->first;
}
const std::vector<Vector3<float>>& NavigationMesh::get_neighbors(const Vector3<float>& vertex) const noexcept
{
return m_vertex_map.at(vertex);
}
bool NavigationMesh::empty() const
{
return m_vertex_map.empty();
}
std::vector<uint8_t> NavigationMesh::serialize() const noexcept
{
auto dump_to_vector = []<typename T>(const T& t, std::vector<uint8_t>& vec)
{
for (size_t i = 0; i < sizeof(t); i++)
vec.push_back(*(reinterpret_cast<const uint8_t*>(&t) + i));
};
std::vector<uint8_t> raw;
for (const auto& [vertex, neighbors]: m_vertex_map)
{
const auto neighbors_count = neighbors.size();
dump_to_vector(vertex, raw);
dump_to_vector(neighbors_count, raw);
for (const auto& neighbor: neighbors)
dump_to_vector(neighbor, raw);
}
return raw;
}
void NavigationMesh::deserialize(const std::vector<uint8_t>& raw) noexcept
{
auto load_from_vector = [](const std::vector<uint8_t>& vec, size_t& offset, auto& value)
{
if (offset + sizeof(value) > vec.size())
{
throw std::runtime_error("Deserialize: Invalid input data size.");
}
std::copy_n(vec.data() + offset, sizeof(value), reinterpret_cast<uint8_t*>(&value));
offset += sizeof(value);
};
m_vertex_map.clear();
size_t offset = 0;
while (offset < raw.size())
{
Vector3<float> vertex;
load_from_vector(raw, offset, vertex);
uint16_t neighbors_count;
load_from_vector(raw, offset, neighbors_count);
std::vector<Vector3<float>> neighbors;
neighbors.reserve(neighbors_count);
for (size_t i = 0; i < neighbors_count; ++i)
{
Vector3<float> neighbor;
load_from_vector(raw, offset, neighbor);
neighbors.push_back(neighbor);
}
m_vertex_map.emplace(vertex, std::move(neighbors));
}
}
} // namespace omath::pathfinding
@@ -1 +0,0 @@
target_sources(omath PRIVATE ProjPredEngineLegacy.cpp Projectile.cpp Target.cpp ProjPredEngineAVX2.cpp ProjPredEngine.cpp)
@@ -1,10 +0,0 @@
//
// Created by Vlad on 2/23/2025.
//
#include "omath/projectile_prediction/ProjPredEngine.hpp"
namespace omath::projectile_prediction
{
} // namespace omath::projectile_prediction
@@ -1,68 +0,0 @@
#include "omath/projectile_prediction/ProjPredEngineLegacy.hpp"
#include <cmath>
#include <omath/Angles.hpp>
namespace omath::projectile_prediction
{
ProjPredEngineLegacy::ProjPredEngineLegacy(const float gravityConstant, const float simulationTimeStep,
const float maximumSimulationTime, const float distanceTolerance) :
m_gravityConstant(gravityConstant), m_simulationTimeStep(simulationTimeStep),
m_maximumSimulationTime(maximumSimulationTime), m_distanceTolerance(distanceTolerance)
{
}
std::optional<Vector3<float>> ProjPredEngineLegacy::MaybeCalculateAimPoint(const Projectile& projectile,
const Target& target) const
{
for (float time = 0.f; time < m_maximumSimulationTime; time += m_simulationTimeStep)
{
const auto predictedTargetPosition = target.PredictPosition(time, m_gravityConstant);
const auto projectilePitch = MaybeCalculateProjectileLaunchPitchAngle(projectile, predictedTargetPosition);
if (!projectilePitch.has_value()) [[unlikely]]
continue;
if (!IsProjectileReachedTarget(predictedTargetPosition, projectile, projectilePitch.value(), time))
continue;
const auto delta2d = (predictedTargetPosition - projectile.m_origin).Length2D();
const auto height = delta2d * std::tan(angles::DegreesToRadians(projectilePitch.value()));
return Vector3(predictedTargetPosition.x, predictedTargetPosition.y, projectile.m_origin.z + height);
}
return std::nullopt;
}
std::optional<float>
ProjPredEngineLegacy::MaybeCalculateProjectileLaunchPitchAngle(const Projectile& projectile,
const Vector3<float>& targetPosition) const
{
const auto bulletGravity = m_gravityConstant * projectile.m_gravityScale;
const auto delta = targetPosition - projectile.m_origin;
const auto distance2d = delta.Length2D();
const auto distance2dSqr = distance2d * distance2d;
const auto launchSpeedSqr = projectile.m_launchSpeed * projectile.m_launchSpeed;
float root = launchSpeedSqr * launchSpeedSqr -
bulletGravity * (bulletGravity * distance2dSqr + 2.0f * delta.z * launchSpeedSqr);
if (root < 0.0f) [[unlikely]]
return std::nullopt;
root = std::sqrt(root);
const float angle = std::atan((launchSpeedSqr - root) / (bulletGravity * distance2d));
return angles::RadiansToDegrees(angle);
}
bool ProjPredEngineLegacy::IsProjectileReachedTarget(const Vector3<float>& targetPosition, const Projectile& projectile,
const float pitch, const float time) const
{
const auto yaw = projectile.m_origin.ViewAngleTo(targetPosition).y;
const auto projectilePosition = projectile.PredictPosition(pitch, yaw, time, m_gravityConstant);
return projectilePosition.DistTo(targetPosition) <= m_distanceTolerance;
}
} // namespace omath::projectile_prediction
@@ -1,21 +0,0 @@
//
// Created by Vlad on 6/9/2024.
//
#include "omath/projectile_prediction/Projectile.hpp"
#include <omath/engines/Source/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::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
-11
View File
@@ -1,11 +0,0 @@
//
// Created by Vlad on 6/9/2024.
//
#include "omath/projectile_prediction/Projectile.hpp"
namespace omath::prediction
{
}
@@ -1,14 +1,23 @@
// //
// Created by Vlad on 2/23/2025. // Created by Vlad on 2/23/2025.
// //
#include "omath/projectile_prediction/ProjPredEngineAVX2.hpp" #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 namespace omath::projectile_prediction
{ {
std::optional<Vector3<float>> ProjPredEngineAVX2::MaybeCalculateAimPoint(const Projectile& projectile, std::optional<Vector3<float>>
const Target& target) const ProjPredEngineAvx2::maybe_calculate_aim_point([[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 bulletGravity = m_gravityConstant * projectile.m_gravityScale;
const float v0 = projectile.m_launchSpeed; const float v0 = projectile.m_launchSpeed;
const float v0Sqr = v0 * v0; const float v0Sqr = v0 * v0;
@@ -19,16 +28,16 @@ namespace omath::projectile_prediction
for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep * SIMD_FACTOR) for (; currentTime <= m_maximumSimulationTime; currentTime += m_simulationTimeStep * SIMD_FACTOR)
{ {
const __m256 times = const __m256 times
_mm256_setr_ps(currentTime, currentTime + m_simulationTimeStep, = _mm256_setr_ps(currentTime, currentTime + m_simulationTimeStep,
currentTime + m_simulationTimeStep * 2, currentTime + m_simulationTimeStep * 3, currentTime + m_simulationTimeStep * 2, currentTime + m_simulationTimeStep * 3,
currentTime + m_simulationTimeStep * 4, currentTime + m_simulationTimeStep * 5, currentTime + m_simulationTimeStep * 4, currentTime + m_simulationTimeStep * 5,
currentTime + m_simulationTimeStep * 6, currentTime + m_simulationTimeStep * 7); currentTime + m_simulationTimeStep * 6, currentTime + m_simulationTimeStep * 7);
const __m256 targetX = const __m256 targetX
_mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x)); = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.x), times, _mm256_set1_ps(target.m_origin.x));
const __m256 targetY = const __m256 targetY
_mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y)); = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.y), times, _mm256_set1_ps(target.m_origin.y));
const __m256 timesSq = _mm256_mul_ps(times, times); const __m256 timesSq = _mm256_mul_ps(times, times);
const __m256 targetZ = _mm256_fmadd_ps(_mm256_set1_ps(target.m_velocity.z), 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_fnmadd_ps(_mm256_set1_ps(0.5f * m_gravityConstant), timesSq,
@@ -103,24 +112,32 @@ namespace omath::projectile_prediction
} }
return std::nullopt; return std::nullopt;
#else
throw std::runtime_error(
std::format("{} AVX2 feature is not enabled!", std::source_location::current().function_name()));
#endif
} }
ProjPredEngineAVX2::ProjPredEngineAVX2(const float gravityConstant, const float simulationTimeStep, ProjPredEngineAvx2::ProjPredEngineAvx2(const float gravity_constant, const float simulation_time_step,
const float maximumSimulationTime) : const float maximum_simulation_time)
m_gravityConstant(gravityConstant), m_simulationTimeStep(maximumSimulationTime), : m_gravity_constant(gravity_constant), m_simulation_time_step(simulation_time_step),
m_maximumSimulationTime(simulationTimeStep) m_maximum_simulation_time(maximum_simulation_time)
{ {
} }
std::optional<float> ProjPredEngineAVX2::CalculatePitch(const Vector3<float>& projOrigin, const Vector3<float>& targetPos, std::optional<float> ProjPredEngineAvx2::calculate_pitch([[maybe_unused]] const Vector3<float>& proj_origin,
const float bulletGravity, const float v0, const float time) [[maybe_unused]] const Vector3<float>& target_pos,
[[maybe_unused]] const float bullet_gravity,
[[maybe_unused]] const float v0,
[[maybe_unused]] const float time)
{ {
#if defined(OMATH_USE_AVX2) && defined(__i386__) && defined(__x86_64__)
if (time <= 0.0f) if (time <= 0.0f)
return std::nullopt; return std::nullopt;
const Vector3 delta = targetPos - projOrigin; const Vector3 delta = target_pos - proj_origin;
const float dSqr = delta.x * delta.x + delta.y * delta.y; const float dSqr = delta.x * delta.x + delta.y * delta.y;
const float h = delta.z; const float h = delta.z;
const float term = h + 0.5f * bulletGravity * time * time; const float term = h + 0.5f * bullet_gravity * time * time;
const float requiredV0Sqr = (dSqr + term * term) / (time * time); const float requiredV0Sqr = (dSqr + term * term) / (time * time);
const float v0Sqr = v0 * v0; const float v0Sqr = v0 * v0;
@@ -130,9 +147,12 @@ namespace omath::projectile_prediction
if (dSqr == 0.0f) if (dSqr == 0.0f)
return term >= 0.0f ? 90.0f : -90.0f; return term >= 0.0f ? 90.0f : -90.0f;
const float d = std::sqrt(dSqr); const float d = std::sqrt(dSqr);
const float tanTheta = term / d; const float tanTheta = term / d;
return angles::RadiansToDegrees(std::atan(tanTheta)); 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 } // namespace omath::projectile_prediction

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