Compare commits

...

84 Commits

Author SHA1 Message Date
eeb6e40909 Merge pull request #35 from orange-cpp/u/orange-cpp/imrpoved-color
U/orange cpp/imrpoved color
2025-03-29 17:43:36 +03:00
d72ad663cd added new methods 2025-03-29 05:41:55 +03:00
3e75d32f59 fixed style 2025-03-29 04:00:35 +03:00
a8ce5cbaa0 added vcpkg imgui package auto link 2025-03-29 01:56:09 +03:00
79f76a0755 added new option 2025-03-29 01:53:04 +03:00
5773cc7798 improved imgui handling 2025-03-24 21:48:51 +03:00
b6b0184523 fixed for clang 2025-03-24 06:48:51 +03:00
a797dd134a Update README.md 2025-03-24 06:46:02 +03:00
dc43411bd2 fixed unity view matrix building 2025-03-24 06:30:09 +03:00
8959161904 Merge pull request #34 from orange-cpp/u/orange-cpp/add-unity
U/orange cpp/add unity
2025-03-23 01:20:16 +03:00
5d5bd215b2 fix 2025-03-23 01:17:05 +03:00
a48a257648 removed comment 2025-03-23 01:12:46 +03:00
ffba4e256a name fix 2025-03-23 01:06:36 +03:00
d9219cdddb naming fixed 2025-03-23 01:02:11 +03:00
5a1014a239 fix 2025-03-23 00:57:58 +03:00
74f2241bcf uncommented test 2025-03-23 00:52:12 +03:00
8977557a61 fix 2025-03-22 17:41:01 +03:00
481d7b85df improved camera 2025-03-22 17:39:40 +03:00
2b59fb6aa2 updated formulas 2025-03-22 08:36:06 +03:00
4f037a1952 added unity engine tests 2025-03-22 08:12:16 +03:00
ef11183c3f added camera files 2025-03-22 04:26:54 +03:00
326d8baaae Update README.md 2025-03-21 05:31:44 +03:00
e46067b0b9 fixed tests includes 2025-03-21 04:58:28 +03:00
68ac7f7b3d Merge pull request #33 from orange-cpp/u/orange-cpp/changed-file-naming
U/orange cpp/changed file naming
2025-03-21 04:50:56 +03:00
17de6d407c style fix 2025-03-21 04:48:38 +03:00
59d686e252 fix 2025-03-21 04:47:01 +03:00
713af1b772 fix 2025-03-21 04:46:23 +03:00
a8922230b3 fixed name 2025-03-21 04:45:02 +03:00
b8d79eb8b4 fixed example 2025-03-21 04:43:57 +03:00
5acd166d8f fixed include names 2025-03-21 04:40:59 +03:00
c7dda0ff10 changed source files naming 2025-03-21 04:30:17 +03:00
2688d977a9 change 2025-03-21 04:21:31 +03:00
Vladislav Alpatov
b9ac44a901 renamed headers 2025-03-21 04:17:42 +03:00
35658b1f6d Merge pull request #32 from orange-cpp/u/orange-cpp/examples
U/orange cpp/examples
2025-03-19 20:17:45 +03:00
8f4b61319f disabled tests by default 2025-03-19 20:13:06 +03:00
832c2ea5ef removed inline functions 2025-03-19 20:07:44 +03:00
50c336e044 added example 2025-03-19 19:16:22 +03:00
Vladislav Alpatov
e80e22bd5b added some files 2025-03-19 18:58:35 +03:00
27576ed761 added alias 2025-03-19 18:50:47 +03:00
f85243e892 improved print method 2025-03-19 00:56:56 +03:00
9b6d0beb03 Update README.md 2025-03-17 18:20:40 +03:00
ee9829af22 Merge pull request #31 from orange-cpp/u/orange-cpp/IWEngine
Added Infinity Ward Engine Support
2025-03-17 09:20:51 +03:00
cd452b0397 updated comment 2025-03-17 09:14:42 +03:00
2fa0c500a7 added magic number 2025-03-17 08:59:41 +03:00
0740d0778c added iw engine files 2025-03-17 07:20:13 +03:00
f5c271cfa6 changed naming of engines section 2025-03-17 05:27:00 +03:00
064a31f527 Merge pull request #30 from orange-cpp/u/orange-cpp/imgui-integration
ImGUI Vector integration
2025-03-17 04:12:39 +03:00
e5d0adf247 changed default option 2025-03-17 04:11:49 +03:00
8fc107ec0f fix 2025-03-17 04:07:21 +03:00
6dd72d2448 added convertors 2025-03-17 03:56:09 +03:00
c76f6e91b0 fix 2025-03-17 02:41:08 +03:00
d1d06c24ca unit tests buid off by defalut 2025-03-15 19:13:06 +03:00
169011e238 fixed Vec3 Vec4 2025-03-15 19:11:31 +03:00
934ca0da0a added explicit constructor for angle and comment for angle 2025-03-15 18:57:41 +03:00
4200ef63a6 improved mat & camera interface 2025-03-15 18:53:18 +03:00
58e2c3b5b7 fixed members inititalization miss match 2025-03-14 19:43:50 +03:00
Vladislav Alpatov
c3202a3bc3 patch 2025-03-01 21:32:02 +03:00
Vladislav Alpatov
39ab9d065d added option to disable avx2 2025-03-01 21:30:53 +03:00
Vladislav Alpatov
ed372a1c78 fixed for clang support 2025-03-01 21:22:44 +03:00
70313f5ae0 Merge pull request #29 from orange-cpp/u/orange-cpp/template-vectors
Added template Vectors 2d 3d 4d
2025-03-01 21:17:42 +03:00
Vladislav Alpatov
978656b573 refactored 2025-03-01 21:17:03 +03:00
Vladislav Alpatov
a0f746b84c fixed style 2025-03-01 21:15:26 +03:00
Vladislav Alpatov
6d0d267743 now template 2025-03-01 21:11:46 +03:00
9ba3bc754a removed define 2025-02-23 21:56:28 +03:00
3d1844fa0e Merge pull request #28 from orange-cpp/u/orange-cpp/avx2-prediction
U/orange cpp/avx2 prediction
2025-02-23 16:32:27 +03:00
f21d29c6c2 added legacy impl 2025-02-23 10:10:35 +03:00
28a35d5bc9 added more classes 2025-02-23 09:57:29 +03:00
d9684ff73f read me update 2025-02-22 23:34:45 +03:00
900501f37e added language mention 2025-02-22 23:34:45 +03:00
5639cd0eb5 added AVX2 2025-02-22 23:34:45 +03:00
244d01c313 Merge pull request #27 from orange-cpp/u/orange-cpp/unity-build-support
added unity build support
2025-02-22 23:33:03 +03:00
e31ffac103 added unity build support 2025-02-22 23:32:29 +03:00
ae87257adf Merge pull request #26 from orange-cpp/u/orange-cpp/improved-astar
Improved A*
2025-02-22 23:06:33 +03:00
906f5099d1 improvement 2025-02-16 10:57:03 +03:00
96e4e1c9d6 added new method added concept for mat type 2025-02-16 10:06:04 +03:00
872dbe146f Merge pull request #25 from orange-cpp/u/orange-cpp/hotfix
improved cmake+hotfix of clang support
2025-01-17 16:59:30 +03:00
e0dcb65e3f improved cmake+hotfix of clang support 2025-01-17 16:56:47 +03:00
d0c532df39 hot fix 2025-01-06 05:36:27 +03:00
31907ceca3 Merge pull request #24 from orange-cpp/u/orange-cpp/improved-triangle-class
U/orange cpp/improved triangle class
2025-01-06 05:19:27 +03:00
afcfed4834 path 2025-01-06 05:17:42 +03:00
835fd110ba fix 2025-01-06 05:15:12 +03:00
29629a737d added some methods 2025-01-06 05:08:32 +03:00
6a324e8c0e improvement 2025-01-06 04:42:43 +03:00
42c84f2523 added midpoint for triangle class 2025-01-06 04:30:03 +03:00
103 changed files with 2165 additions and 1063 deletions

View File

@@ -1,28 +1,69 @@
cmake_minimum_required(VERSION 3.26) cmake_minimum_required(VERSION 3.26)
project(omath VERSION 1.0.1) project(omath VERSION 1.0.1 LANGUAGES CXX)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}") option(OMATH_BUILD_TESTS "Build unit tests" OFF)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}")
option(OMATH_BUILD_TESTS "Build unit tests" ON)
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON) option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF) option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types to imgui types" OFF)
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
if (OMATH_BUILD_AS_SHARED_LIBRARY) if (OMATH_BUILD_AS_SHARED_LIBRARY)
add_library(omath SHARED source/Vector3.cpp) add_library(omath SHARED source/Matrix.cpp)
else() else()
add_library(omath STATIC source/Vector3.cpp add_library(omath STATIC source/Matrix.cpp)
include/omath/engines/OpenGL/Constants.hpp
include/omath/engines/OpenGL/Formulas.hpp
include/omath/engines/OpenGL/Camera.hpp)
endif() endif()
target_compile_definitions(omath PUBLIC OMATH_EXPORT) add_library(omath::omath ALIAS omath)
if (OMATH_IMGUI_INTEGRATION)
target_compile_definitions(omath PUBLIC OMATH_IMGUI_INTEGRATION)
# IMGUI is being linked as submodule
if(TARGET imgui)
target_link_libraries(omath PUBLIC imgui)
install(TARGETS imgui
EXPORT omathTargets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
else()
# Assume that IMGUI linked via VCPKG.
find_package(imgui CONFIG REQUIRED)
target_link_libraries(omath PUBLIC imgui::imgui)
endif()
endif()
if (OMATH_USE_AVX2)
target_compile_definitions(omath PUBLIC OMATH_USE_AVX2)
endif()
set_target_properties(omath PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/${CMAKE_BUILD_TYPE}"
UNITY_BUILD ON
UNITY_BUILD_BATCH_SIZE 20
CXX_STANDARD 23
CXX_STANDARD_REQUIRED ON)
if (OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
set_target_properties(omath PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_compile_options(omath PRIVATE -mavx2 -mfma)
endif()
target_compile_features(omath PUBLIC cxx_std_23)
add_subdirectory(source) add_subdirectory(source)
@@ -31,6 +72,10 @@ if(OMATH_BUILD_TESTS)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
if (OMATH_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR) if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND OMATH_THREAT_WARNING_AS_ERROR)
target_compile_options(omath PRIVATE /W4 /WX) target_compile_options(omath PRIVATE /W4 /WX)
elseif(OMATH_THREAT_WARNING_AS_ERROR) elseif(OMATH_THREAT_WARNING_AS_ERROR)

View File

@@ -1,6 +1,6 @@
<div align = center> <div align = center>
![banner](https://i.imgur.com/sjtpKi8.png) ![banner](https://i.imgur.com/SM9ccP6.png)
![GitHub License](https://img.shields.io/github/license/orange-cpp/omath) ![GitHub License](https://img.shields.io/github/license/orange-cpp/omath)
![GitHub contributors](https://img.shields.io/github/contributors/orange-cpp/omath) ![GitHub contributors](https://img.shields.io/github/contributors/orange-cpp/omath)
@@ -12,13 +12,21 @@
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!
|ENGINE |SUPPORT|
|--------|-------|
|Source |✅YES |
|Unity |✅YES |
|IWEngine|✅YES |
|Unreal |❌NO |
## ⏬ Getting Started ## ⏬ Getting Started
### Prerequisites ### Prerequisites
@@ -51,7 +59,7 @@ For detailed commands on installing different versions and more information, ple
3. Build the project using CMake: 3. Build the project using CMake:
``` ```
cmake --preset windows-release -S . cmake --preset windows-release -S .
cmake --build cmake-build/build/windows-release --target server -j 6 cmake --build cmake-build/build/windows-release --target omath -j 6
``` ```
Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**. Use **\<platform\>-\<build configuration\>** preset to build siutable version for yourself. Like **windows-release** or **linux-release**.
## ❔ Usage ## ❔ Usage
@@ -72,8 +80,11 @@ TEST(UnitTestProjection, IsPointOnScreen)
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 even advanced projectile aimbot
[Watch Video](https://youtu.be/lM_NJ1yCunw?si=5E87OrQMeypxSJ3E)
</details> </details>
## 🫵🏻 Contributing ## 🫵🏻 Contributing

4
examples/CMakeLists.txt Normal file
View File

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

View File

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

View File

@@ -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
{
public:
constexpr Color(float r, float g, float b, float a) : Vector4(r,g,b,a)
{
Clamp(0.f, 1.f);
}
constexpr explicit Color() : Vector4()
{
}
[[nodiscard]]
constexpr static Color FromRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
return Color{Vector4(r, g, b, a) / 255.f};
}
[[nodiscard]]
constexpr static Color FromHSV(float hue, float saturation, float value)
{
float r{}, g{}, b{};
hue = std::clamp(hue, 0.f, 1.f);
const int i = static_cast<int>(hue * 6.f);
const float f = hue * 6 - i;
const float p = value * (1 - saturation);
const float q = value * (1 - f * saturation);
const float t = value * (1 - (1 - f) * saturation);
switch (i % 6)
{
case 0: r = value, g = t, b = p; break;
case 1: r = q, g = value, b = p; break;
case 2: r = p, g = value, b = t; break;
case 3: r = p, g = q, b = value; break;
case 4: r = t, g = p, b = value; break;
case 5: r = value, g = p, b = q; break;
default: return {0.f, 0.f, 0.f, 0.f};
}
return {r, g, b, 1.f};
}
[[nodiscard]]
constexpr HSV ToHSV() const
{
HSV hsvData;
const float& red = x;
const float& green = y;
const float& blue = z;
const float max = std::max({red, green, blue});
const float min = std::min({red, green, blue});
const float delta = max - min;
if (delta == 0.f)
hsvData.m_hue = 0.f;
else if (max == red)
hsvData.m_hue = 60.f * (std::fmodf(((green - blue) / delta), 6.f));
else if (max == green)
hsvData.m_hue = 60.f * (((blue - red) / delta) + 2.f);
else if (max == blue)
hsvData.m_hue = 60.f * (((red - green) / delta) + 4.f);
if (hsvData.m_hue < 0.f)
hsvData.m_hue += 360.f;
hsvData.m_hue /= 360.f;
hsvData.m_saturation = max == 0.f ? 0.f : delta / max;
hsvData.m_value = max;
return hsvData;
}
constexpr explicit Color(const Vector4& vec) : Vector4(vec)
{
Clamp(0.f, 1.f);
}
[[nodiscard]]
constexpr Color Blend(const Color& other, float ratio) const
{
return Color( (*this * (1.f - ratio)) + (other * ratio) );
}
[[nodiscard]] static constexpr Color Red() {return {1.f, 0.f, 0.f, 1.f};}
[[nodiscard]] static constexpr Color Green() {return {0.f, 1.f, 0.f, 1.f};}
[[nodiscard]] static constexpr Color Blue() {return {0.f, 0.f, 1.f, 1.f};}
};
[[nodiscard]]
constexpr Color Blend(const Color& first, const Color& second, float ratio)
{
return Color{first * (1.f - std::clamp(ratio, 0.f, 1.f)) + second * ratio};
}
}

View File

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

View File

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

View File

@@ -3,7 +3,7 @@
// //
#pragma once #pragma once
#include "omath/Angles.hpp" #include "omath/angles.hpp"
#include <algorithm> #include <algorithm>
namespace omath namespace omath
@@ -19,7 +19,7 @@ namespace omath
class Angle class Angle
{ {
Type m_angle; Type m_angle;
constexpr Angle(const Type& degrees) constexpr explicit Angle(const Type& degrees)
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
m_angle = angles::WrapAngle(degrees, min, max); m_angle = angles::WrapAngle(degrees, min, max);
@@ -36,7 +36,7 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr static Angle FromDegrees(const Type& degrees) constexpr static Angle FromDegrees(const Type& degrees)
{ {
return {degrees}; return Angle{degrees};
} }
constexpr Angle() : m_angle(0) constexpr Angle() : m_angle(0)
{ {
@@ -45,7 +45,7 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr static Angle FromRadians(const Type& degrees) constexpr static Angle FromRadians(const Type& degrees)
{ {
return {angles::RadiansToDegrees<Type>(degrees)}; return Angle{angles::RadiansToDegrees<Type>(degrees)};
} }
[[nodiscard]] [[nodiscard]]
@@ -96,7 +96,6 @@ namespace omath
return Cos() / Sin(); return Cos() / Sin();
} }
[[nodiscard]]
constexpr Angle& operator+=(const Angle& other) constexpr Angle& operator+=(const Angle& other)
{ {
if constexpr (flags == AngleFlags::Normalized) if constexpr (flags == AngleFlags::Normalized)
@@ -116,7 +115,6 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr std::partial_ordering operator<=>(const Angle& other) const = default; constexpr std::partial_ordering operator<=>(const Angle& other) const = default;
[[nodiscard]]
constexpr Angle& operator-=(const Angle& other) constexpr Angle& operator-=(const Angle& other)
{ {
return operator+=(-other); return operator+=(-other);
@@ -146,7 +144,7 @@ namespace omath
[[nodiscard]] [[nodiscard]]
constexpr Angle operator-() const constexpr Angle operator-() const
{ {
return {-m_angle}; return Angle{-m_angle};
} }
}; };
} }

View File

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

View File

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

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

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

View File

@@ -1,54 +0,0 @@
//
// Created by Orange on 12/23/2024.
//
#pragma once
#include "Constants.hpp"
namespace omath::opengl
{
[[nodiscard]]
inline Vector3 ForwardVector(const ViewAngles& angles)
{
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
[[nodiscard]]
inline Vector3 RightVector(const ViewAngles& angles)
{
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
[[nodiscard]]
inline Vector3 UpVector(const ViewAngles& angles)
{
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
}
[[nodiscard]] inline Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3& cam_origin)
{
return MatCameraView<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},
};
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
//
// Created by Vlad on 3/22/2025.
//
#pragma once
#include <omath/vector3.hpp>
#include <omath/mat.hpp>
#include <omath/angle.hpp>
#include <omath/view_angles.hpp>
namespace omath::unity_engine
{
constexpr Vector3<float> kAbsUp = {0, 1, 0};
constexpr Vector3<float> kAbsRight = {1, 0, 0};
constexpr Vector3<float> kAbsForward = {0, 0, 1};
using Mat4x4 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat3x3 = Mat<4, 4, float, MatStoreType::ROW_MAJOR>;
using Mat1x3 = Mat<1, 3, float, MatStoreType::ROW_MAJOR>;
using PitchAngle = Angle<float, -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

View File

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

View File

@@ -4,10 +4,11 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <iomanip>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include "Vector3.hpp" #include "omath/vector3.hpp"
namespace omath namespace omath
{ {
@@ -22,16 +23,25 @@ namespace omath
COLUMN_MAJOR COLUMN_MAJOR
}; };
template<typename M1, typename M2>
concept MatTemplateEqual =
(M1::rows == M2::rows) && (M1::columns == M2::columns) &&
std::is_same_v<typename M1::value_type, typename M2::value_type> &&
(M1::store_type == M2::store_type);
template<size_t Rows = 0, size_t Columns = 0, class Type = float, MatStoreType StoreType = MatStoreType::ROW_MAJOR> template<size_t Rows = 0, size_t Columns = 0, class Type = float, MatStoreType StoreType = MatStoreType::ROW_MAJOR>
requires std::is_arithmetic_v<Type> requires std::is_arithmetic_v<Type>
class Mat final class Mat final
{ {
public: public:
constexpr Mat() constexpr Mat() noexcept
{ {
Clear(); Clear();
} }
constexpr static MatStoreType GetStoreOrdering()
[[nodiscard]]
constexpr static MatStoreType GetStoreOrdering() noexcept
{ {
return StoreType; return StoreType;
} }
@@ -65,6 +75,7 @@ namespace omath
m_data = other.m_data; m_data = other.m_data;
} }
[[nodiscard]]
constexpr Type& operator[](const size_t row, const size_t col) constexpr Type& operator[](const size_t row, const size_t col)
{ {
return At(row, col); return At(row, col);
@@ -93,7 +104,8 @@ namespace omath
return {Rows, Columns}; return {Rows, Columns};
} }
[[nodiscard]] constexpr const Type& At(const size_t rowIndex, const size_t columnIndex) const [[nodiscard]]
constexpr const Type& At(const size_t rowIndex, const size_t columnIndex) const
{ {
if (rowIndex >= Rows || columnIndex >= Columns) if (rowIndex >= Rows || columnIndex >= Columns)
throw std::out_of_range("Index out of range"); throw std::out_of_range("Index out of range");
@@ -170,6 +182,7 @@ namespace omath
return *this = *this * other; return *this = *this * other;
} }
[[nodiscard]]
constexpr Mat operator*(const Type& f) const noexcept constexpr Mat operator*(const Type& f) const noexcept
{ {
Mat result(*this); Mat result(*this);
@@ -185,6 +198,7 @@ namespace omath
return *this; return *this;
} }
[[nodiscard]]
constexpr Mat operator/(const Type& f) const noexcept constexpr Mat operator/(const Type& f) const noexcept
{ {
Mat result(*this); Mat result(*this);
@@ -283,15 +297,20 @@ namespace omath
std::string ToString() const noexcept std::string ToString() const noexcept
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "[[";
for (size_t i = 0; i < Rows; ++i) for (size_t i = 0; i < Rows; ++i)
{ {
if (i > 0)
oss << " [";
for (size_t j = 0; j < Columns; ++j) for (size_t j = 0; j < Columns; ++j)
{ {
oss << At(i, j); oss << std::setw(9) << std::fixed << std::setprecision(3) << At(i, j);
if (j != Columns - 1) if (j != Columns - 1)
oss << ' '; oss << ", ";
} }
oss << '\n'; oss << (i == Rows - 1 ? "]]" : "]\n");
} }
return oss.str(); return oss.str();
} }
@@ -326,21 +345,21 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3& vector) noexcept constexpr static Mat<1, 4, Type, St> MatRowFromVector(const Vector3<Type>& vector) noexcept
{ {
return {{vector.x, vector.y, vector.z, 1}}; return {{vector.x, vector.y, vector.z, 1}};
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3& vector) noexcept constexpr static Mat<4, 1, Type, St> MatColumnFromVector(const Vector3<Type>& vector) noexcept
{ {
return {{vector.x}, {vector.y}, {vector.z}, {1}}; return {{vector.x}, {vector.y}, {vector.z}, {1}};
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3& diff) noexcept constexpr Mat<4, 4, Type, St> MatTranslation(const Vector3<Type>& diff) noexcept
{ {
return return
{ {
@@ -392,8 +411,8 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]] [[nodiscard]]
static Mat<4, 4, Type, St> MatCameraView(const Vector3& forward, const Vector3& right, const Vector3& up, static Mat<4, 4, Type, St> MatCameraView(const Vector3<Type>& forward, const Vector3<Type>& right,
const Vector3& cameraOrigin) noexcept const Vector3<Type>& up, const Vector3<Type>& cameraOrigin) noexcept
{ {
return Mat<4, 4, Type, St> return Mat<4, 4, Type, St>
{ {
@@ -411,4 +430,30 @@ namespace omath
{ {
return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll); return MatRotationAxisZ(angles.yaw) * MatRotationAxisY(angles.pitch) * MatRotationAxisX(angles.roll);
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> MatPerspectiveLeftHanded(const float fieldOfView, const float aspectRatio, const float near,
const float far) noexcept
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f);
return {{1.f / (aspectRatio * fovHalfTan), 0.f, 0.f, 0.f},
{0.f, 1.f / fovHalfTan, 0.f, 0.f},
{0.f, 0.f, (far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, 1.f, 0.f}};
}
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard]]
Mat<4, 4, Type, St> MatPerspectiveRightHanded(const float fieldOfView, const float aspectRatio, const float near,
const float far) noexcept
{
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f);
return {{1.f / (aspectRatio * fovHalfTan), 0.f, 0.f, 0.f},
{0.f, 1.f / fovHalfTan, 0.f, 0.f},
{0.f, 0.f, -(far + near) / (far - near), -(2.f * near * far) / (far - near)},
{0.f, 0.f, -1.f, 0.f}};
}
} // namespace omath } // namespace omath

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,11 +5,11 @@
#pragma once #pragma once
#include <expected> #include <expected>
#include <omath/Mat.hpp> #include <omath/angle.hpp>
#include <omath/Vector3.hpp> #include <omath/mat.hpp>
#include "ErrorCodes.hpp" #include <omath/vector3.hpp>
#include <omath/Angle.hpp>
#include <type_traits> #include <type_traits>
#include "omath/projection/error_codes.hpp"
namespace omath::projection namespace omath::projection
{ {
@@ -24,22 +24,22 @@ namespace omath::projection
return m_width / m_height; return m_width / m_height;
} }
}; };
using FieldOfView = const Angle<float, 0.f, 180.f, AngleFlags::Clamped>; using FieldOfView = Angle<float, 0.f, 180.f, AngleFlags::Clamped>;
template<class Mat4x4Type, class ViewAnglesType> template<class Mat4x4Type, class ViewAnglesType>
class Camera class Camera
{ {
public: public:
virtual ~Camera() = default; virtual ~Camera() = default;
Camera(const Vector3& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort, Camera(const Vector3<float>& position, const ViewAnglesType& viewAngles, const ViewPort& viewPort,
const FieldOfView& fov, const float near, const float far) : const FieldOfView& fov, const float near, const float far) :
m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near), m_viewPort(viewPort), m_fieldOfView(fov), m_farPlaneDistance(far), m_nearPlaneDistance(near),
m_viewAngles(viewAngles), m_origin(position) m_viewAngles(viewAngles), m_origin(position)
{ {
} }
virtual void LookAt(const Vector3& target) = 0; protected:
virtual void LookAt(const Vector3<float>& target) = 0;
[[nodiscard]] virtual Mat4x4Type CalcViewMatrix() const = 0; [[nodiscard]] virtual Mat4x4Type CalcViewMatrix() const = 0;
@@ -50,40 +50,43 @@ namespace omath::projection
return CalcProjectionMatrix() * CalcViewMatrix(); return CalcProjectionMatrix() * CalcViewMatrix();
} }
public:
[[nodiscard]] const Mat4x4Type& GetViewProjectionMatrix() const
{
if (!m_viewProjectionMatrix.has_value())
m_viewProjectionMatrix = CalcViewProjectionMatrix();
return m_viewProjectionMatrix.value();
}
void SetFieldOfView(const FieldOfView& fov) void SetFieldOfView(const FieldOfView& fov)
{ {
m_fieldOfView = fov; m_fieldOfView = fov;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
} }
void SetNearPlane(const float near) void SetNearPlane(const float near)
{ {
m_nearPlaneDistance = near; m_nearPlaneDistance = near;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
} }
void SetFarPlane(const float far) void SetFarPlane(const float far)
{ {
m_farPlaneDistance = far; m_farPlaneDistance = far;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
} }
void SetViewAngles(const ViewAnglesType& viewAngles) void SetViewAngles(const ViewAnglesType& viewAngles)
{ {
m_viewAngles = viewAngles; m_viewAngles = viewAngles;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
} }
void SetOrigin(const Vector3& origin) void SetOrigin(const Vector3<float>& origin)
{ {
m_origin = origin; m_origin = origin;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
} }
void SetViewPort(const ViewPort& viewPort) void SetViewPort(const ViewPort& viewPort)
{ {
m_viewPort = viewPort; m_viewPort = viewPort;
m_viewProjectionMatrix = CalcViewProjectionMatrix();
} }
[[nodiscard]] const FieldOfView& GetFieldOfView() const [[nodiscard]] const FieldOfView& GetFieldOfView() const
@@ -106,17 +109,26 @@ namespace omath::projection
return m_viewAngles; return m_viewAngles;
} }
[[nodiscard]] const Vector3& GetOrigin() const [[nodiscard]] const Vector3<float>& GetOrigin() const
{ {
return m_origin; return m_origin;
} }
[[nodiscard]] std::expected<Vector3, Error> WorldToScreen(const Vector3& worldPosition) const [[nodiscard]] std::expected<Vector3<float>, Error> WorldToScreen(const Vector3<float>& worldPosition) const
{ {
if (!m_viewProjectionMatrix.has_value()) auto normalizedCords = WorldToViewPort(worldPosition);
m_viewProjectionMatrix = CalcViewProjectionMatrix();
auto projected = m_viewProjectionMatrix.value() * MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(worldPosition); if (!normalizedCords.has_value())
return std::unexpected{normalizedCords.error()};
return NdcToScreenPosition(*normalizedCords);
}
[[nodiscard]] std::expected<Vector3<float>, Error> WorldToViewPort(const Vector3<float>& worldPosition) const
{
auto projected = GetViewProjectionMatrix() *
MatColumnFromVector<float, Mat4x4Type::GetStoreOrdering()>(worldPosition);
if (projected.At(3, 0) == 0.0f) if (projected.At(3, 0) == 0.0f)
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
@@ -126,10 +138,7 @@ namespace omath::projection
if (IsNdcOutOfBounds(projected)) if (IsNdcOutOfBounds(projected))
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); 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; return Vector3<float>{projected.At(0, 0), projected.At(1, 0), projected.At(2, 0)};
const auto screenPositionY = (-projected.At(1,0)+1) / 2.f * m_viewPort.m_height;
return Vector3{screenPositionX, screenPositionY, projected.At(2,0)};
} }
protected: protected:
@@ -143,14 +152,24 @@ namespace omath::projection
ViewAnglesType m_viewAngles; ViewAnglesType m_viewAngles;
Vector3 m_origin; Vector3<float> m_origin;
private: private:
template<class Type> template<class Type>
[[nodiscard]] [[nodiscard]]
constexpr static bool IsNdcOutOfBounds(const Type& ndc) constexpr static bool IsNdcOutOfBounds(const Type& ndc)
{ {
return std::ranges::any_of( ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; }); return std::ranges::any_of(ndc.RawArray(), [](const auto& val) { return val < -1 || val > 1; });
}
[[nodiscard]] Vector3<float> NdcToScreenPosition(const Vector3<float>& ndc) const
{
return
{
(ndc.x + 1.f) / 2.f * m_viewPort.m_width,
(1.f - ndc.y) / 2.f * m_viewPort.m_height,
ndc.z
};
} }
}; };
} // namespace omath::projection } // namespace omath::projection

View File

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

View File

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

View File

@@ -5,11 +5,10 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <functional>
#include "omath/Vector2.hpp"
#include "omath/Angle.hpp"
#include <expected> #include <expected>
#include <functional>
#include "omath/angle.hpp"
#include "omath/vector2.hpp"
namespace omath namespace omath
{ {
@@ -19,16 +18,17 @@ namespace omath
IMPOSSIBLE_BETWEEN_ANGLE, IMPOSSIBLE_BETWEEN_ANGLE,
}; };
class Vector3 : public Vector2 template<class Type> requires std::is_arithmetic_v<Type>
class Vector3 : public Vector2<Type>
{ {
public: public:
float z = 0.f; Type z = static_cast<Type>(0);
constexpr Vector3(const float x, const float y, const float z) : Vector2(x, y), z(z) { } constexpr Vector3(const Type& x, const Type& y, const Type& z) : Vector2<Type>(x, y), z(z) { }
constexpr Vector3() : Vector2() {}; constexpr Vector3() : Vector2<Type>() {};
[[nodiscard]] constexpr bool operator==(const Vector3& src) const [[nodiscard]] constexpr bool operator==(const Vector3& src) const
{ {
return Vector2::operator==(src) && (src.z == z); return Vector2<Type>::operator==(src) && (src.z == z);
} }
[[nodiscard]] constexpr bool operator!=(const Vector3& src) const [[nodiscard]] constexpr bool operator!=(const Vector3& src) const
@@ -38,7 +38,7 @@ namespace omath
constexpr Vector3& operator+=(const Vector3& v) constexpr Vector3& operator+=(const Vector3& v)
{ {
Vector2::operator+=(v); Vector2<Type>::operator+=(v);
z += v.z; z += v.z;
return *this; return *this;
@@ -46,7 +46,7 @@ namespace omath
constexpr Vector3& operator-=(const Vector3& v) constexpr Vector3& operator-=(const Vector3& v)
{ {
Vector2::operator-=(v); Vector2<Type>::operator-=(v);
z -= v.z; z -= v.z;
return *this; return *this;
@@ -54,7 +54,7 @@ namespace omath
constexpr Vector3& operator*=(const float fl) constexpr Vector3& operator*=(const float fl)
{ {
Vector2::operator*=(fl); Vector2<Type>::operator*=(fl);
z *= fl; z *= fl;
return *this; return *this;
@@ -62,7 +62,7 @@ namespace omath
constexpr Vector3& operator*=(const Vector3& v) constexpr Vector3& operator*=(const Vector3& v)
{ {
Vector2::operator*=(v); Vector2<Type>::operator*=(v);
z *= v.z; z *= v.z;
return *this; return *this;
@@ -70,7 +70,7 @@ namespace omath
constexpr Vector3& operator/=(const Vector3& v) constexpr Vector3& operator/=(const Vector3& v)
{ {
Vector2::operator/=(v); Vector2<Type>::operator/=(v);
z /= v.z; z /= v.z;
return *this; return *this;
@@ -78,7 +78,7 @@ namespace omath
constexpr Vector3& operator+=(const float fl) constexpr Vector3& operator+=(const float fl)
{ {
Vector2::operator+=(fl); Vector2<Type>::operator+=(fl);
z += fl; z += fl;
return *this; return *this;
@@ -86,7 +86,7 @@ namespace omath
constexpr Vector3& operator/=(const float fl) constexpr Vector3& operator/=(const float fl)
{ {
Vector2::operator/=(fl); Vector2<Type>::operator/=(fl);
z /= fl; z /= fl;
return *this; return *this;
@@ -94,7 +94,7 @@ namespace omath
constexpr Vector3& operator-=(const float fl) constexpr Vector3& operator-=(const float fl)
{ {
Vector2::operator-=(fl); Vector2<Type>::operator-=(fl);
z -= fl; z -= fl;
return *this; return *this;
@@ -102,117 +102,117 @@ namespace omath
constexpr Vector3& Abs() constexpr Vector3& Abs()
{ {
Vector2::Abs(); Vector2<Type>::Abs();
z = z < 0.f ? -z : z; z = z < 0.f ? -z : z;
return *this; return *this;
} }
[[nodiscard]] constexpr float DistToSqr(const Vector3& vOther) const [[nodiscard]] constexpr Type DistToSqr(const Vector3& vOther) const
{ {
return (*this - vOther).LengthSqr(); return (*this - vOther).LengthSqr();
} }
[[nodiscard]] constexpr float Dot(const Vector3& vOther) const [[nodiscard]] constexpr Type Dot(const Vector3& vOther) const
{ {
return Vector2::Dot(vOther) + z * vOther.z; return Vector2<Type>::Dot(vOther) + z * vOther.z;
} }
#ifndef _MSC_VER #ifndef _MSC_VER
[[nodiscard]] constexpr float Length() const [[nodiscard]] constexpr Type Length() const
{ {
return std::hypot(x, y, z); return std::hypot(x, y, z);
} }
[[nodiscard]] constexpr float Length2D() const [[nodiscard]] constexpr Type Length2D() const
{ {
return Vector2::Length(); return Vector2::Length();
} }
[[nodiscard]] float DistTo(const Vector3& vOther) const [[nodiscard]] Type DistTo(const Vector3& vOther) const
{ {
return (*this - vOther).Length(); return (*this - vOther).Length();
} }
[[nodiscard]] constexpr Vector3 Normalized() const [[nodiscard]] constexpr Vector3 Normalized() const
{ {
const float length = this->Length(); const Type length = this->Length();
return length != 0 ? *this / length : *this; return length != 0 ? *this / length : *this;
} }
#else #else
[[nodiscard]] float Length() const [[nodiscard]] Type Length() const
{ {
return std::hypot(x, y, z); return std::hypot(this->x, this->y, z);
} }
[[nodiscard]] Vector3 Normalized() const [[nodiscard]] Vector3 Normalized() const
{ {
const float length = this->Length(); const Type length = this->Length();
return length != 0 ? *this / length : *this; return length != 0 ? *this / length : *this;
} }
[[nodiscard]] float Length2D() const [[nodiscard]] Type Length2D() const
{ {
return Vector2::Length(); return Vector2<Type>::Length();
} }
[[nodiscard]] float DistTo(const Vector3& vOther) const [[nodiscard]] Type DistTo(const Vector3& vOther) const
{ {
return (*this - vOther).Length(); return (*this - vOther).Length();
} }
#endif #endif
[[nodiscard]] constexpr float LengthSqr() const [[nodiscard]] constexpr Type LengthSqr() const
{ {
return Vector2::LengthSqr() + z * z; return Vector2<Type>::LengthSqr() + z * z;
} }
[[nodiscard]] constexpr Vector3 operator-() const [[nodiscard]] constexpr Vector3 operator-() const
{ {
return {-x, -y, -z}; return {-this->x, -this->y, -z};
} }
[[nodiscard]] constexpr Vector3 operator+(const Vector3& v) const [[nodiscard]] constexpr Vector3 operator+(const Vector3& v) const
{ {
return {x + v.x, y + v.y, z + v.z}; return {this->x + v.x, this->y + v.y, z + v.z};
} }
[[nodiscard]] constexpr Vector3 operator-(const Vector3& v) const [[nodiscard]] constexpr Vector3 operator-(const Vector3& v) const
{ {
return {x - v.x, y - v.y, z - v.z}; return {this->x - v.x, this->y - v.y, z - v.z};
} }
[[nodiscard]] constexpr Vector3 operator*(const float fl) const [[nodiscard]] constexpr Vector3 operator*(const float fl) const
{ {
return {x * fl, y * fl, z * fl}; return {this->x * fl, this->y * fl, z * fl};
} }
[[nodiscard]] constexpr Vector3 operator*(const Vector3& v) const [[nodiscard]] constexpr Vector3 operator*(const Vector3& v) const
{ {
return {x * v.x, y * v.y, z * v.z}; return {this->x * v.x, this->y * v.y, z * v.z};
} }
[[nodiscard]] constexpr Vector3 operator/(const float fl) const [[nodiscard]] constexpr Vector3 operator/(const float fl) const
{ {
return {x / fl, y / fl, z / fl}; return {this->x / fl, this->y / fl, z / fl};
} }
[[nodiscard]] constexpr Vector3 operator/(const Vector3& v) const [[nodiscard]] constexpr Vector3 operator/(const Vector3& v) const
{ {
return {x / v.x, y / v.y, z / v.z}; return {this->x / v.x, this->y / v.y, z / v.z};
} }
[[nodiscard]] constexpr Vector3 Cross(const Vector3 &v) const [[nodiscard]] constexpr Vector3 Cross(const Vector3 &v) const
{ {
return return
{ {
y * v.z - z * v.y, this->y * v.z - z * v.y,
z * v.x - x * v.z, z * v.x - this->x * v.z,
x * v.y - y * v.x this->x * v.y - this->y * v.x
}; };
} }
[[nodiscard]] constexpr float Sum() const [[nodiscard]] constexpr Type Sum() const
{ {
return Sum2D() + z; return Sum2D() + z;
} }
@@ -228,16 +228,35 @@ namespace omath
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::FromRadians(std::acos(Dot(other) / bottom)); return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::FromRadians(std::acos(Dot(other) / bottom));
} }
[[nodiscard]] constexpr float Sum2D() const [[nodiscard]] bool IsPerpendicular(const Vector3& other) const
{ {
return Vector2::Sum(); if (const auto angle = AngleBetween(other))
return angle->AsDegrees() == 90.f;
return false;
} }
[[nodiscard]] Vector3 ViewAngleTo(const Vector3& other) const; [[nodiscard]] constexpr Type Sum2D() const
[[nodiscard]] std::tuple<float, float, float> AsTuple() const
{ {
return std::make_tuple(x, y, z); return Vector2<Type>::Sum();
}
[[nodiscard]] constexpr std::tuple<Type, Type, Type> AsTuple() const
{
return std::make_tuple(this->x, this->y, z);
}
[[nodiscard]] Vector3 ViewAngleTo(const Vector3 &other) const
{
const float distance = DistTo(other);
const auto delta = other - *this;
return
{
angles::RadiansToDegrees(std::asin(delta.z / distance)),
angles::RadiansToDegrees(std::atan2(delta.y, delta.x)),
0
};
} }
}; };
} }
@@ -245,9 +264,9 @@ namespace omath
namespace std namespace std
{ {
template<> template<>
struct hash<omath::Vector3> struct hash<omath::Vector3<float>>
{ {
std::size_t operator()(const omath::Vector3& vec) const noexcept std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{ {
std::size_t hash = 0; std::size_t hash = 0;
constexpr std::hash<float> hasher; constexpr std::hash<float> hasher;

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

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

View File

@@ -1,13 +1,9 @@
target_sources(omath PRIVATE target_sources(omath PRIVATE
Vector3.cpp matrix.cpp
Matrix.cpp
color.cpp color.cpp
Vector4.cpp
Vector2.cpp
Triangle3d.cpp
) )
add_subdirectory(prediction) add_subdirectory(projectile_prediction)
add_subdirectory(pathfinding) add_subdirectory(pathfinding)
add_subdirectory(projection) add_subdirectory(projection)
add_subdirectory(collision) add_subdirectory(collision)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,19 +1,19 @@
// //
// Created by Orange on 12/23/2024. // Created by Orange on 12/23/2024.
// //
#include "omath/engines/OpenGL/Camera.hpp" #include "omath/engines/opengl_engine/camera.hpp"
#include "omath/engines/OpenGL/Formulas.hpp" #include "omath/engines/opengl_engine/formulas.hpp"
namespace omath::opengl namespace omath::opengl_engine
{ {
Camera::Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, Camera::Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const Angle<float, 0, 180, AngleFlags::Clamped>& fov, const float near, const float far) : 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) projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{ {
} }
void Camera::LookAt([[maybe_unused]] const Vector3& target) void Camera::LookAt([[maybe_unused]] const Vector3<float>& target)
{ {
const float distance = m_origin.DistTo(target); const float distance = m_origin.DistTo(target);
const auto delta = target - m_origin; const auto delta = target - m_origin;
@@ -25,7 +25,7 @@ namespace omath::opengl
} }
Mat4x4 Camera::CalcViewMatrix() const Mat4x4 Camera::CalcViewMatrix() const
{ {
return opengl::CalcViewMatrix(m_viewAngles, m_origin); return opengl_engine::CalcViewMatrix(m_viewAngles, m_origin);
} }
Mat4x4 Camera::CalcProjectionMatrix() const Mat4x4 Camera::CalcProjectionMatrix() const
{ {

View File

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

View File

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

View File

@@ -1,19 +1,19 @@
// //
// Created by Orange on 12/4/2024. // Created by Orange on 12/4/2024.
// //
#include "omath/engines/Source/Camera.hpp" #include "omath/engines/source_engine/camera.hpp"
#include "omath/engines/Source/Formulas.hpp" #include "omath/engines/source_engine/formulas.hpp"
namespace omath::source namespace omath::source_engine
{ {
Camera::Camera(const Vector3& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort, Camera::Camera(const Vector3<float>& position, const ViewAngles& viewAngles, const projection::ViewPort& viewPort,
const projection::FieldOfView& fov, const float near, const float far) : const projection::FieldOfView& fov, const float near, const float far) :
projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far) projection::Camera<Mat4x4, ViewAngles>(position, viewAngles, viewPort, fov, near, far)
{ {
} }
void Camera::LookAt(const Vector3& target) void Camera::LookAt(const Vector3<float>& target)
{ {
const float distance = m_origin.DistTo(target); const float distance = m_origin.DistTo(target);
const auto delta = target - m_origin; const auto delta = target - m_origin;
@@ -26,7 +26,7 @@ namespace omath::source
Mat4x4 Camera::CalcViewMatrix() const Mat4x4 Camera::CalcViewMatrix() const
{ {
return source::CalcViewMatrix(m_viewAngles, m_origin); return source_engine::CalcViewMatrix(m_viewAngles, m_origin);
} }
Mat4x4 Camera::CalcProjectionMatrix() const Mat4x4 Camera::CalcProjectionMatrix() const

View File

@@ -1,47 +1,40 @@
// //
// Created by Orange on 12/4/2024. // Created by Vlad on 3/19/2025.
// //
#pragma once #include <omath/engines/source_engine/formulas.hpp>
#include "Constants.hpp"
namespace omath::source
namespace omath::source_engine
{ {
[[nodiscard]] Vector3<float> ForwardVector(const ViewAngles& angles)
inline Vector3 ForwardVector(const ViewAngles& angles)
{ {
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsForward); const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsForward);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
} }
[[nodiscard]] Vector3<float> RightVector(const ViewAngles& angles)
inline Vector3 RightVector(const ViewAngles& angles)
{ {
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsRight); const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsRight);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
} }
Vector3<float> UpVector(const ViewAngles& angles)
[[nodiscard]]
inline Vector3 UpVector(const ViewAngles& angles)
{ {
const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsUp); const auto vec = MatRotation(angles) * MatColumnFromVector(kAbsUp);
return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)}; return {vec.At(0, 0), vec.At(1, 0), vec.At(2, 0)};
} }
[[nodiscard]] inline Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3& cam_origin) Mat4x4 CalcViewMatrix(const ViewAngles& angles, const Vector3<float>& cam_origin)
{ {
return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin); return MatCameraView(ForwardVector(angles), RightVector(angles), UpVector(angles), cam_origin);
} }
Mat4x4 CalcPerspectiveProjectionMatrix(const float fieldOfView, const float aspectRatio, const float near,
[[nodiscard]] const float far)
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 // NOTE: Need magic number to fix fov calculation, since source inherit Quake proj matrix calculation
// and use tricky projection matrix formula.
constexpr auto kMultiplyFactor = 0.75f; constexpr auto kMultiplyFactor = 0.75f;
const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor; const float fovHalfTan = std::tan(angles::DegreesToRadians(fieldOfView) / 2.f) * kMultiplyFactor;
@@ -51,7 +44,6 @@ namespace omath::source
{0, 1.f / (fovHalfTan), 0, 0}, {0, 1.f / (fovHalfTan), 0, 0},
{0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)}, {0, 0, (far + near) / (far - near), -(2.f * far * near) / (far - near)},
{0, 0, 1, 0}, {0, 0, 1, 0},
}; };
} }
} // namespace omath::source } // namespace omath::source_engine

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
#include "omath/Matrix.hpp" #include "omath/matrix.hpp"
#include "omath/Angles.hpp" #include "omath/angles.hpp"
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
#include <complex> #include <complex>
@@ -315,7 +315,7 @@ namespace omath
}; };
} }
Matrix Matrix::TranslationMatrix(const Vector3& diff) Matrix Matrix::TranslationMatrix(const Vector3<float>& diff)
{ {
return { return {
{1.f, 0.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f},
@@ -325,7 +325,7 @@ namespace omath
}; };
} }
Matrix Matrix::OrientationMatrix(const Vector3& forward, const Vector3& right, const Vector3& up) Matrix Matrix::OrientationMatrix(const Vector3<float>& forward, const Vector3<float>& right, const Vector3<float>& up)
{ {
return { return {
{right.x, up.x, forward.x, 0.f}, {right.x, up.x, forward.x, 0.f},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,35 +2,35 @@
// Created by Orange on 11/23/2024. // Created by Orange on 11/23/2024.
// //
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/engines/OpenGL/Camera.hpp> #include <omath/engines/opengl_engine/camera.hpp>
#include <omath/engines/OpenGL/Constants.hpp> #include <omath/engines/opengl_engine/constants.hpp>
#include <omath/engines/OpenGL/Formulas.hpp> #include <omath/engines/opengl_engine/formulas.hpp>
TEST(UnitTestOpenGL, ForwardVector) TEST(UnitTestOpenGL, ForwardVector)
{ {
const auto forward = omath::opengl::ForwardVector({}); const auto forward = omath::opengl_engine::ForwardVector({});
EXPECT_EQ(forward, omath::opengl::kAbsForward); EXPECT_EQ(forward, omath::opengl_engine::kAbsForward);
} }
TEST(UnitTestOpenGL, RightVector) TEST(UnitTestOpenGL, RightVector)
{ {
const auto right = omath::opengl::RightVector({}); const auto right = omath::opengl_engine::RightVector({});
EXPECT_EQ(right, omath::opengl::kAbsRight); EXPECT_EQ(right, omath::opengl_engine::kAbsRight);
} }
TEST(UnitTestOpenGL, UpVector) TEST(UnitTestOpenGL, UpVector)
{ {
const auto up = omath::opengl::UpVector({}); const auto up = omath::opengl_engine::UpVector({});
EXPECT_EQ(up, omath::opengl::kAbsUp); EXPECT_EQ(up, omath::opengl_engine::kAbsUp);
} }
TEST(UnitTestOpenGL, ProjectTargetMovedFromCamera) TEST(UnitTestOpenGL, ProjectTargetMovedFromCamera)
{ {
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::opengl::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); const auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
for (float distance = -10.f; distance > -1000.f; distance -= 0.01f) for (float distance = -10.f; distance > -1000.f; distance -= 0.01f)
@@ -50,7 +50,7 @@ TEST(UnitTestOpenGL, ProjectTargetMovedFromCamera)
TEST(UnitTestOpenGL, CameraSetAndGetFov) TEST(UnitTestOpenGL, CameraSetAndGetFov)
{ {
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f); constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::opengl::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f); auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f); EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f);
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f)); cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
@@ -60,9 +60,9 @@ TEST(UnitTestOpenGL, CameraSetAndGetFov)
TEST(UnitTestOpenGL, CameraSetAndGetOrigin) TEST(UnitTestOpenGL, CameraSetAndGetOrigin)
{ {
auto cam = omath::opengl::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f); auto cam = omath::opengl_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
EXPECT_EQ(cam.GetOrigin(), omath::Vector3{}); EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f)); cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f); EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);

View File

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

View File

@@ -0,0 +1,77 @@
//
// Created by Orange on 11/27/2024.
//
#include <gtest/gtest.h>
#include <omath/engines/unity_engine/camera.hpp>
#include <omath/engines/unity_engine/constants.hpp>
#include <omath/engines/unity_engine/formulas.hpp>
TEST(UnitTestUnityEngine, ForwardVector)
{
const auto forward = omath::unity_engine::ForwardVector({});
EXPECT_EQ(forward, omath::unity_engine::kAbsForward);
}
TEST(UnitTestUnityEngine, RightVector)
{
const auto right = omath::unity_engine::RightVector({});
EXPECT_EQ(right, omath::unity_engine::kAbsRight);
}
TEST(UnitTestUnityEngine, UpVector)
{
const auto up = omath::unity_engine::UpVector({});
EXPECT_EQ(up, omath::unity_engine::kAbsUp);
}
TEST(UnitTestUnityEngine, ProjectTargetMovedFromCamera)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(60.f);
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.01f, 1000.f);
for (float distance = 0.02f; distance < 100.f; distance += 0.01f)
{
const auto projected = cam.WorldToScreen({0, 0, distance});
EXPECT_TRUE(projected.has_value());
if (!projected.has_value())
continue;
EXPECT_NEAR(projected->x, 640, 0.00001f);
EXPECT_NEAR(projected->y, 360, 0.00001f);
}
}
TEST(UnitTestUnityEngine, Project)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(60.f);
const auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1280.f, 720.f}, fov, 0.03f, 1000.f);
const auto proj = cam.WorldToScreen({5.f, 3, 10.f});
std::println("{} {}", proj->x, proj->y);
}
TEST(UnitTestUnityEngine, CameraSetAndGetFov)
{
constexpr auto fov = omath::projection::FieldOfView::FromDegrees(90.f);
auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, fov, 0.01f, 1000.f);
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 90.f);
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}
TEST(UnitTestUnityEngine, CameraSetAndGetOrigin)
{
auto cam = omath::unity_engine::Camera({0, 0, 0}, {}, {1920.f, 1080.f}, {}, 0.01f, 1000.f);
EXPECT_EQ(cam.GetOrigin(), omath::Vector3<float>{});
cam.SetFieldOfView(omath::projection::FieldOfView::FromDegrees(50.f));
EXPECT_EQ(cam.GetFieldOfView().AsDegrees(), 50.f);
}

View File

@@ -1,15 +0,0 @@
#include <gtest/gtest.h>
#include <omath/prediction/Engine.hpp>
TEST(UnitTestPrediction, PredictionTest)
{
constexpr omath::prediction::Target target{
.m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_isAirborne = false};
constexpr omath::prediction::Projectile proj = {.m_origin = {3,2,1}, .m_launchSpeed = 5000, .m_gravityScale= 0.4};
const auto viewPoint = omath::prediction::Engine(400, 1.f / 1000.f, 50, 5.f).MaybeCalculateAimPoint(proj, target);
const auto [pitch, yaw, _] = proj.m_origin.ViewAngleTo(viewPoint.value()).AsTuple();
EXPECT_NEAR(42.547142, pitch, 0.0001f);
EXPECT_NEAR(-1.181189, yaw, 0.0001f);
}

View File

@@ -2,7 +2,7 @@
// Created by Vlad on 18.08.2024. // Created by Vlad on 18.08.2024.
// //
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/pathfinding/Astar.hpp> #include <omath/pathfinding/a_star.hpp>
TEST(UnitTestAstar, FindingRightPath) TEST(UnitTestAstar, FindingRightPath)

View File

@@ -2,8 +2,7 @@
// Created by Orange on 11/30/2024. // Created by Orange on 11/30/2024.
// //
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/Angles.hpp> #include <omath/angles.hpp>
#include <omath/Angle.hpp>
TEST(UnitTestAngles, RadiansToDeg) TEST(UnitTestAngles, RadiansToDeg)
{ {

View File

@@ -2,7 +2,7 @@
// Created by Vlad on 01.09.2024. // Created by Vlad on 01.09.2024.
// //
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/Color.hpp> #include <omath/color.hpp>
using namespace omath; using namespace omath;
@@ -63,9 +63,9 @@ TEST_F(UnitTestColor, FromHSV)
TEST_F(UnitTestColor, ToHSV) TEST_F(UnitTestColor, ToHSV)
{ {
HSV hsv = color1.ToHSV(); // Red color HSV hsv = color1.ToHSV(); // Red color
EXPECT_FLOAT_EQ(hsv.m_hue, 0.0f); EXPECT_FLOAT_EQ(hsv.hue, 0.0f);
EXPECT_FLOAT_EQ(hsv.m_saturation, 1.0f); EXPECT_FLOAT_EQ(hsv.saturation, 1.0f);
EXPECT_FLOAT_EQ(hsv.m_value, 1.0f); EXPECT_FLOAT_EQ(hsv.value, 1.0f);
} }
// Test color blending // Test color blending
@@ -106,7 +106,7 @@ TEST_F(UnitTestColor, BlendVector3)
{ {
constexpr Color v1(1.0f, 0.0f, 0.0f, 1.f); // Red constexpr Color v1(1.0f, 0.0f, 0.0f, 1.f); // Red
constexpr Color v2(0.0f, 1.0f, 0.0f, 1.f); // Green constexpr Color v2(0.0f, 1.0f, 0.0f, 1.f); // Green
constexpr Color blended = Blend(v1, v2, 0.5f); constexpr Color blended = v1.Blend(v2, 0.5f);
EXPECT_FLOAT_EQ(blended.x, 0.5f); EXPECT_FLOAT_EQ(blended.x, 0.5f);
EXPECT_FLOAT_EQ(blended.y, 0.5f); EXPECT_FLOAT_EQ(blended.y, 0.5f);
EXPECT_FLOAT_EQ(blended.z, 0.0f); EXPECT_FLOAT_EQ(blended.z, 0.0f);

View File

@@ -1,7 +1,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "omath/collision/LineTracer.hpp" #include "omath/collision/line_tracer.hpp"
#include "omath/Triangle3d.hpp" #include "omath/triangle.hpp"
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
using namespace omath; using namespace omath;
using namespace omath::collision; using namespace omath::collision;
@@ -10,10 +10,10 @@ class LineTracerTest : public ::testing::Test
{ {
protected: protected:
// Set up common variables for use in each test // Set up common variables for use in each test
Vector3 vertex1{0.0f, 0.0f, 0.0f}; Vector3<float> vertex1{0.0f, 0.0f, 0.0f};
Vector3 vertex2{1.0f, 0.0f, 0.0f}; Vector3<float> vertex2{1.0f, 0.0f, 0.0f};
Vector3 vertex3{0.0f, 1.0f, 0.0f}; Vector3<float> vertex3{0.0f, 1.0f, 0.0f};
Triangle3d triangle{vertex1, vertex2, vertex3}; Triangle<Vector3<float>> triangle{vertex1, vertex2, vertex3};
}; };
// Test that a ray intersecting the triangle returns false for CanTraceLine // Test that a ray intersecting the triangle returns false for CanTraceLine
@@ -71,7 +71,7 @@ TEST_F(LineTracerTest, TriangleFarBeyondRayEndPoint)
constexpr Ray ray{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}; constexpr Ray ray{{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
// Define a triangle far beyond the ray's endpoint // Define a triangle far beyond the ray's endpoint
const Triangle3d distantTriangle{ constexpr Triangle<Vector3<float>> distantTriangle{
{1000.0f, 1000.0f, 1000.0f}, {1001.0f, 1000.0f, 1000.0f}, {1000.0f, 1001.0f, 1000.0f} {1000.0f, 1000.0f, 1000.0f}, {1001.0f, 1000.0f, 1000.0f}, {1000.0f, 1001.0f, 1000.0f}
}; };

View File

@@ -1,7 +1,7 @@
// UnitTestMat.cpp // UnitTestMat.cpp
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "omath/Mat.hpp" #include "omath/mat.hpp"
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
using namespace omath; using namespace omath;
@@ -127,7 +127,7 @@ TEST_F(UnitTestMat, ToString)
{ {
const std::string str = m2.ToString(); const std::string str = m2.ToString();
EXPECT_FALSE(str.empty()); EXPECT_FALSE(str.empty());
EXPECT_EQ(str, "1 2\n3 4\n"); EXPECT_EQ(str, "[[ 1.000, 2.000]\n [ 3.000, 4.000]]");
} }
// Test assignment operators // Test assignment operators

View File

@@ -2,8 +2,8 @@
// Created by vlad on 5/18/2024. // Created by vlad on 5/18/2024.
// //
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/Matrix.hpp> #include <omath/matrix.hpp>
#include "omath/Vector3.hpp" #include "omath/vector3.hpp"
using namespace omath; using namespace omath;

View File

@@ -0,0 +1,17 @@
#include <gtest/gtest.h>
#include <omath/projectile_prediction/proj_pred_engine_legacy.hpp>
TEST(UnitTestPrediction, PredictionTest)
{
constexpr omath::projectile_prediction::Target target{
.m_origin = {100, 0, 90}, .m_velocity = {0, 0, 0}, .m_isAirborne = false};
constexpr omath::projectile_prediction::Projectile proj = {
.m_origin = {3, 2, 1}, .m_launchSpeed = 5000, .m_gravityScale = 0.4};
const auto viewPoint =
omath::projectile_prediction::ProjPredEngineLegacy(400, 1.f / 1000.f, 50, 5.f).MaybeCalculateAimPoint(proj, target);
const auto [pitch, yaw, _] = proj.m_origin.ViewAngleTo(viewPoint.value()).AsTuple();
EXPECT_NEAR(42.547142, pitch, 0.01f);
EXPECT_NEAR(-1.181189, yaw, 0.01f);
}

View File

@@ -3,15 +3,14 @@
// //
#include <complex> #include <complex>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/Matrix.hpp> #include <omath/engines/source_engine/camera.hpp>
#include <omath/engines/Source/Camera.hpp> #include <omath/projection/camera.hpp>
#include <omath/projection/Camera.hpp>
#include <print> #include <print>
TEST(UnitTestProjection, Projection) TEST(UnitTestProjection, Projection)
{ {
const auto x = omath::Angle<float, 0.f, 180.f, omath::AngleFlags::Clamped>::FromDegrees(90.f); const auto x = omath::Angle<float, 0.f, 180.f, omath::AngleFlags::Clamped>::FromDegrees(90.f);
auto cam = omath::source::Camera({0, 0, 0}, omath::source::ViewAngles{}, {1920.f, 1080.f}, x, 0.01f, 1000.f); auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, x, 0.01f, 1000.f);
const auto projected = cam.WorldToScreen({1000, 0, 50}); const auto projected = cam.WorldToScreen({1000, 0, 50});
std::print("{} {} {}", projected->x, projected->y, projected->z); std::print("{} {} {}", projected->x, projected->y, projected->z);

View File

@@ -0,0 +1,132 @@
//
// Created by Orange on 1/6/2025.
//
#include <cmath> // For std::sqrt, std::isinf, std::isnan
#include <gtest/gtest.h>
#include <omath/vector3.hpp>
#include "omath/triangle.hpp"
using namespace omath;
class UnitTestTriangle : public ::testing::Test
{
protected:
// Define some Triangles to use in tests
Triangle<Vector3<float>> t1;
Triangle<Vector3<float>> t2;
Triangle<Vector3<float>> t3;
constexpr void SetUp() override
{
// Triangle with vertices (0, 0, 0), (1, 0, 0), (0, 1, 0)
t1 = Triangle<Vector3<float>>(
Vector3(0.0f, 0.0f, 0.0f),
Vector3(1.0f, 0.0f, 0.0f),
Vector3(0.0f, 1.0f, 0.0f)
);
// Triangle with vertices (1, 2, 3), (4, 5, 6), (7, 8, 9)
t2 = Triangle<Vector3<float>>(
Vector3(1.0f, 2.0f, 3.0f),
Vector3(4.0f, 5.0f, 6.0f),
Vector3(7.0f, 8.0f, 9.0f)
);
// An isosceles right triangle
t3 = Triangle<Vector3<float>>(
Vector3(0.0f, 0.0f, 0.0f),
Vector3(2.0f, 0.0f, 0.0f),
Vector3(0.0f, 2.0f, 0.0f)
);
}
};
// Test constructor and vertices
TEST_F(UnitTestTriangle, Constructor)
{
constexpr Triangle<Vector3<float>> t(
Vector3(1.0f, 2.0f, 3.0f),
Vector3(4.0f, 5.0f, 6.0f),
Vector3(7.0f, 8.0f, 9.0f)
);
EXPECT_FLOAT_EQ(t.m_vertex1.x, 1.0f);
EXPECT_FLOAT_EQ(t.m_vertex1.y, 2.0f);
EXPECT_FLOAT_EQ(t.m_vertex1.z, 3.0f);
EXPECT_FLOAT_EQ(t.m_vertex2.x, 4.0f);
EXPECT_FLOAT_EQ(t.m_vertex2.y, 5.0f);
EXPECT_FLOAT_EQ(t.m_vertex2.z, 6.0f);
EXPECT_FLOAT_EQ(t.m_vertex3.x, 7.0f);
EXPECT_FLOAT_EQ(t.m_vertex3.y, 8.0f);
EXPECT_FLOAT_EQ(t.m_vertex3.z, 9.0f);
}
// Test CalculateNormal
TEST_F(UnitTestTriangle, CalculateNormal)
{
// For t1, the normal should point in the +Z direction (0, 0, 1) or (0, 0, -1)
const Vector3 normal_t1 = t1.CalculateNormal();
// Check if it's normalized and pointed along Z (sign can differ, so use absolute check)
EXPECT_NEAR(std::fabs(normal_t1.z), 1.0f, 1e-5f);
EXPECT_NEAR(normal_t1.Length(), 1.0f, 1e-5f);
// For t3, we expect the normal to be along +Z as well
const Vector3 normal_t3 = t3.CalculateNormal();
EXPECT_NEAR(std::fabs(normal_t3.z), 1.0f, 1e-5f);
}
// Test side lengths
TEST_F(UnitTestTriangle, SideLengths)
{
// For t1 side lengths
EXPECT_FLOAT_EQ(t1.SideALength(), std::sqrt(1.0f)); // distance between (0,0,0) and (1,0,0)
EXPECT_FLOAT_EQ(t1.SideBLength(), std::sqrt(1.0f + 1.0f)); // distance between (4,5,6) & (7,8,9)... but we are testing t1, so let's be accurate:
// Actually, for t1: vertex2=(1,0,0), vertex3=(0,1,0)
// Dist between (0,1,0) and (1,0,0) = sqrt((1-0)^2 + (0-1)^2) = sqrt(1 + 1) = sqrt(2)
EXPECT_FLOAT_EQ(t1.SideBLength(), std::sqrt(2.0f));
// For t3, side a = distance between vertex1=(0,0,0) and vertex2=(2,0,0), which is 2
// side b = distance between vertex3=(0,2,0) and vertex2=(2,0,0), which is sqrt(2^2 + (-2)^2)= sqrt(8)= 2.828...
// We'll just check side a first:
EXPECT_FLOAT_EQ(t3.SideALength(), 2.0f);
// Then side b:
EXPECT_FLOAT_EQ(t3.SideBLength(), std::sqrt(8.0f));
}
// Test side vectors
TEST_F(UnitTestTriangle, SideVectors)
{
const Vector3 sideA_t1 = t1.SideAVector(); // m_vertex1 - m_vertex2
EXPECT_FLOAT_EQ(sideA_t1.x, 0.0f - 1.0f);
EXPECT_FLOAT_EQ(sideA_t1.y, 0.0f - 0.0f);
EXPECT_FLOAT_EQ(sideA_t1.z, 0.0f - 0.0f);
const Vector3 sideB_t1 = t1.SideBVector(); // m_vertex3 - m_vertex2
EXPECT_FLOAT_EQ(sideB_t1.x, 0.0f - 1.0f);
EXPECT_FLOAT_EQ(sideB_t1.y, 1.0f - 0.0f);
EXPECT_FLOAT_EQ(sideB_t1.z, 0.0f - 0.0f);
}
TEST_F(UnitTestTriangle, IsRectangular)
{
EXPECT_TRUE(Triangle<Vector3<float>>({2,0,0}, {}, {0,2,0}).IsRectangular());
}
// Test midpoint
TEST_F(UnitTestTriangle, MidPoint)
{
// For t1, midpoint of (0,0,0), (1,0,0), (0,1,0)
const Vector3 mid1 = t1.MidPoint();
EXPECT_FLOAT_EQ(mid1.x, (0.0f + 1.0f + 0.0f) / 3.0f);
EXPECT_FLOAT_EQ(mid1.y, (0.0f + 0.0f + 1.0f) / 3.0f);
EXPECT_FLOAT_EQ(mid1.z, 0.0f);
// For t2, midpoint of (1,2,3), (4,5,6), (7,8,9)
const Vector3 mid2 = t2.MidPoint();
EXPECT_FLOAT_EQ(mid2.x, (1.0f + 4.0f + 7.0f) / 3.0f);
EXPECT_FLOAT_EQ(mid2.y, (2.0f + 5.0f + 8.0f) / 3.0f);
EXPECT_FLOAT_EQ(mid2.z, (3.0f + 6.0f + 9.0f) / 3.0f);
}

View File

@@ -2,18 +2,18 @@
// Created by Vlad on 02.09.2024. // Created by Vlad on 02.09.2024.
// //
#include <gtest/gtest.h>
#include <omath/Vector2.hpp>
#include <cmath> // For std::isinf and std::isnan
#include <cfloat> // For FLT_MAX and FLT_MIN #include <cfloat> // For FLT_MAX and FLT_MIN
#include <cmath> // For std::isinf and std::isnan
#include <gtest/gtest.h>
#include <omath/vector2.hpp>
using namespace omath; using namespace omath;
class UnitTestVector2 : public ::testing::Test class UnitTestVector2 : public ::testing::Test
{ {
protected: protected:
Vector2 v1; Vector2<float> v1;
Vector2 v2; Vector2<float> v2;
constexpr void SetUp() override constexpr void SetUp() override
{ {
@@ -25,7 +25,7 @@ protected:
// Test constructor and default values // Test constructor and default values
TEST_F(UnitTestVector2, Constructor_Default) TEST_F(UnitTestVector2, Constructor_Default)
{ {
constexpr Vector2 v; constexpr Vector2<float> v;
EXPECT_FLOAT_EQ(v.x, 0.0f); EXPECT_FLOAT_EQ(v.x, 0.0f);
EXPECT_FLOAT_EQ(v.y, 0.0f); EXPECT_FLOAT_EQ(v.y, 0.0f);
} }

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