mirror of
https://github.com/orange-cpp/omath.git
synced 2026-06-09 16:54:35 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f0cfd4cef | |||
| 8c03a07600 | |||
| 498df95e3e | |||
| 7ad0e3f10b | |||
| 4372f429ae | |||
| 077653e5ce | |||
| 5ec26f9def | |||
| f48232cc1d | |||
| 32b1b90414 | |||
| 0b18129eac | |||
| 8983cfc6d9 | |||
| 123184987f | |||
| ac7aeee9be | |||
| 1d8dba6487 | |||
| 18b0b210cf | |||
| 9e08f5bb5c | |||
| a61d3f20b7 | |||
| 4340e83914 | |||
| 1efa28d676 | |||
| f393d0c1c3 | |||
| 55c5bb92da | |||
| 6f203e3a20 | |||
| 038de53783 | |||
| fde3e1dcb9 | |||
| 6153478d6e | |||
| 4a6ddb230b | |||
| bb61e2303e | |||
| 522597c196 | |||
| 9709ba8f61 | |||
| 5111695d84 | |||
| 50bfc3e943 | |||
| 15f2a3917f | |||
| dede0a145d | |||
| 4238c94fc0 | |||
| 6a6c265501 | |||
| d061f67d13 | |||
| 1546d8a90f |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Generated
-1
@@ -3,6 +3,5 @@
|
|||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/extlibs/googletest" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/extlibs/vcpkg" vcs="Git" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
+2
-1
@@ -13,7 +13,7 @@ option(OMATH_IMGUI_INTEGRATION "Omath will define method to convert omath types
|
|||||||
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
|
option(OMATH_BUILD_EXAMPLES "Build example projects with you can learn & play" OFF)
|
||||||
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
|
option(OMATH_STATIC_MSVC_RUNTIME_LIBRARY "Force Omath to link static runtime" OFF)
|
||||||
option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build to improve general performance" ON)
|
option(OMATH_SUPRESS_SAFETY_CHECKS "Supress some safety checks in release build to improve general performance" ON)
|
||||||
option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" ON)
|
option(OMATH_USE_UNITY_BUILD "Will enable unity build to speed up compilation" OFF)
|
||||||
option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" OFF)
|
option(OMATH_ENABLE_LEGACY "Will enable legacy classes that MUST be used ONLY for backward compatibility" OFF)
|
||||||
|
|
||||||
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}")
|
message(STATUS "[${PROJECT_NAME}]: Building on ${CMAKE_HOST_SYSTEM_NAME}")
|
||||||
@@ -100,6 +100,7 @@ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
|||||||
if (OMATH_BUILD_TESTS)
|
if (OMATH_BUILD_TESTS)
|
||||||
add_subdirectory(extlibs)
|
add_subdirectory(extlibs)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_BUILD_TESTS)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (OMATH_BUILD_EXAMPLES)
|
if (OMATH_BUILD_EXAMPLES)
|
||||||
|
|||||||
+2
-2
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
Thanks to everyone who made this possible, including:
|
Thanks to everyone who made this possible, including:
|
||||||
|
|
||||||
- Saikari aka luadebug for VCPKG port.
|
- Saikari aka luadebug for VCPKG port and awesome new initial logo design.
|
||||||
|
|
||||||
And a big hand to everyone else who has contributed over the past!
|
And a big hand to everyone else who has contributed over the past!
|
||||||
|
|
||||||
THANKS! <3
|
THANKS! <3
|
||||||
|
|
||||||
-- Orange++ <orange-cpp@yandex.ru>
|
-- Orange++ <orange_github@proton.me>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (C) 2024-2025 Orange++ <orange-cpp@yandex.ru>
|
Copyright (C) 2024-2025 Orange++ <orange_github@proton.me>
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
||||||
@@ -15,3 +15,14 @@ freely, subject to the following restrictions:
|
|||||||
2. Altered source versions must be plainly marked as such, and must not be
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
misrepresented as being the original software.
|
misrepresented as being the original software.
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
4. If you are an employee, contractor, volunteer, representative,
|
||||||
|
or have any other affiliation (past, present, or future)
|
||||||
|
with any of the following entities:
|
||||||
|
* "Yandex" LLC
|
||||||
|
* "Rutube" LLC
|
||||||
|
Or if you represent or are associated with any legal, organizational, or
|
||||||
|
professional entity providing services to or on behalf of the aforementioned entities:
|
||||||
|
You are expressly forbidden from accessing, using, modifying, distributing, or
|
||||||
|
interacting with the Software and its source code in any form. You must immediately
|
||||||
|
delete or destroy any physical or digital copies of the Software and/or
|
||||||
|
its source code, including any derivative works, tools, or information obtained from the Software.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<div align = center>
|
<div align = center>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
[](https://www.codefactor.io/repository/github/orange-cpp/omath)
|
[](https://www.codefactor.io/repository/github/orange-cpp/omath)
|
||||||
@@ -12,9 +12,24 @@
|
|||||||
[](https://discord.gg/eDgdaWbqwZ)
|
[](https://discord.gg/eDgdaWbqwZ)
|
||||||
[](https://t.me/orangennotes)
|
[](https://t.me/orangennotes)
|
||||||
|
|
||||||
|
OMath is a 100% independent, constexpr template blazingly fast math library that doesn't have legacy C++ code.
|
||||||
|
|
||||||
|
It provides the latest features, is highly customizable, has all for cheat development, DirectX/OpenGL/Vulkan support, premade support for different game engines, much more constexpr stuff than in other libraries and more...
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**[<kbd> <br> Install <br> </kbd>][INSTALL]**
|
||||||
|
**[<kbd> <br> Examples <br> </kbd>][EXAMPLES]**
|
||||||
|
**[<kbd> <br> Contribute <br> </kbd>][CONTRIBUTING]**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Oranges's Math Library (omath) is a comprehensive, open-source library aimed at providing efficient, reliable, and versatile mathematical functions and algorithms. Developed primarily in C++, this library is designed to cater to a wide range of mathematical operations essential in scientific computing, engineering, and academic research.
|
|
||||||
|
|
||||||
<div align = center>
|
<div align = center>
|
||||||
<a href="https://www.star-history.com/#orange-cpp/omath&Date">
|
<a href="https://www.star-history.com/#orange-cpp/omath&Date">
|
||||||
@@ -36,6 +51,29 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
|
|||||||
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
|
- **No Additional Dependencies**: No additional dependencies need to use OMath except unit test execution
|
||||||
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
|
- **Ready for meta-programming**: Omath use templates for common types like Vectors, Matrixes etc, to handle all types!
|
||||||
|
|
||||||
|
# Gallery
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
[](https://youtu.be/lM_NJ1yCunw?si=-Qf5yzDcWbaxAXGQ)
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
![APEX Preview]
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
![BO2 Preview]
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
![CS2 Preview]
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Supported Render Pipelines
|
## Supported Render Pipelines
|
||||||
| ENGINE | SUPPORT |
|
| ENGINE | SUPPORT |
|
||||||
|----------|---------|
|
|----------|---------|
|
||||||
@@ -53,9 +91,6 @@ Oranges's Math Library (omath) is a comprehensive, open-source library aimed at
|
|||||||
| Linux | ✅YES |
|
| Linux | ✅YES |
|
||||||
| Darwin (MacOS) | ✅YES |
|
| Darwin (MacOS) | ✅YES |
|
||||||
|
|
||||||
## ⏬ Installation
|
|
||||||
Please read our [installation guide](https://github.com/orange-cpp/omath/blob/main/INSTALL.md). If this link doesn't work check out INSTALL.md file.
|
|
||||||
|
|
||||||
## ❔ Usage
|
## ❔ Usage
|
||||||
ESP example
|
ESP example
|
||||||
```c++
|
```c++
|
||||||
@@ -77,26 +112,16 @@ for (auto ent: apex_sdk::EntityList::GetAllEntities())
|
|||||||
// esp rendering...
|
// esp rendering...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
## Showcase
|
|
||||||
<details>
|
|
||||||
<summary>OMATH for making cheats (click to open)</summary>
|
|
||||||
|
|
||||||
With `omath/projection` module you can achieve simple ESP hack for powered by Source/Unreal/Unity engine games, like [Apex Legends](https://store.steampowered.com/app/1172470/Apex_Legends/).
|
|
||||||
|
|
||||||

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

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

|
|
||||||
Or even advanced projectile aimbot
|
|
||||||
[Watch Video](https://youtu.be/lM_NJ1yCunw?si=5E87OrQMeypxSJ3E)
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## 🫵🏻 Contributing
|
|
||||||
Contributions to `omath` are welcome! Please read `CONTRIBUTING.md` for details on our code of conduct and the process for submitting pull requests.
|
|
||||||
|
|
||||||
## 📜 License
|
|
||||||
This project is licensed under the ZLIB - see the `LICENSE` file for details.
|
|
||||||
|
|
||||||
## 💘 Acknowledgments
|
## 💘 Acknowledgments
|
||||||
- [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)
|
- [All contributors](https://github.com/orange-cpp/omath/graphs/contributors)
|
||||||
|
|
||||||
|
<!----------------------------------{ Images }--------------------------------->
|
||||||
|
[APEX Preview]: .github/images/showcase/apex.png
|
||||||
|
[BO2 Preview]: .github/images/showcase/cod_bo2.png
|
||||||
|
[CS2 Preview]: .github/images/showcase/cs2.jpeg
|
||||||
|
|
||||||
|
<!----------------------------------{ Buttons }--------------------------------->
|
||||||
|
[INSTALL]: INSTALL.md
|
||||||
|
[CONTRIBUTING]: CONTRIBUTING.md
|
||||||
|
[EXAMPLES]: examples
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
Please report security issues to `orange-cpp@yandex.ru`
|
Please report security issues to `orange_github@proton.me`
|
||||||
|
|||||||
+16
-11
@@ -5,8 +5,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "omath/angles.hpp"
|
#include "omath/angles.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace omath
|
namespace omath
|
||||||
{
|
{
|
||||||
@@ -123,13 +123,13 @@ namespace omath
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr Angle& operator+(const Angle& other) noexcept
|
constexpr Angle operator+(const Angle& other) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (flags == AngleFlags::Normalized)
|
if constexpr (flags == AngleFlags::Normalized)
|
||||||
return {angles::wrap_angle(m_angle + other.m_angle, min, max)};
|
return Angle{angles::wrap_angle(m_angle + other.m_angle, min, max)};
|
||||||
|
|
||||||
else if constexpr (flags == AngleFlags::Clamped)
|
else if constexpr (flags == AngleFlags::Clamped)
|
||||||
return {std::clamp(m_angle + other.m_angle, min, max)};
|
return Angle{std::clamp(m_angle + other.m_angle, min, max)};
|
||||||
|
|
||||||
else
|
else
|
||||||
static_assert(false);
|
static_assert(false);
|
||||||
@@ -138,7 +138,7 @@ namespace omath
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr Angle& operator-(const Angle& other) noexcept
|
constexpr Angle operator-(const Angle& other) noexcept
|
||||||
{
|
{
|
||||||
return operator+(-other);
|
return operator+(-other);
|
||||||
}
|
}
|
||||||
@@ -150,17 +150,22 @@ namespace omath
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace omath
|
} // namespace omath
|
||||||
template<class Type, Type min, Type max, omath::AngleFlags flags>
|
|
||||||
struct std::formatter<omath::Angle<Type, min, max, flags>> // NOLINT(*-dcl58-cpp)
|
template<class T, T MinV, T MaxV, omath::AngleFlags F, class CharT>
|
||||||
|
struct std::formatter<omath::Angle<T, MinV, MaxV, F>, CharT>
|
||||||
{
|
{
|
||||||
|
using AngleT = omath::Angle<T, MinV, MaxV, F>;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr auto parse(std::format_parse_context& ctx)
|
static constexpr auto parse(std::basic_format_parse_context<CharT>& ctx)
|
||||||
|
-> std::basic_format_parse_context<CharT>::iterator
|
||||||
{
|
{
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
[[nodiscard]]
|
template<class FormatContext>
|
||||||
static auto format(const omath::Angle<Type, min, max, flags>& deg, std::format_context& ctx)
|
auto format(const AngleT& deg, FormatContext& ctx) const
|
||||||
{
|
{
|
||||||
return std::format_to(ctx.out(), "{}deg", deg.as_degrees());
|
if constexpr (std::is_same_v<typename FormatContext::char_type, char>)
|
||||||
|
return std::format_to(ctx.out(), "{}deg", deg.as_degrees());
|
||||||
|
return std::format_to(ctx.out(), L"{}deg", deg.as_degrees());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -11,13 +11,6 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef near
|
|
||||||
#undef near
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef far
|
|
||||||
#undef far
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace omath
|
namespace omath
|
||||||
{
|
{
|
||||||
@@ -88,7 +81,7 @@ namespace omath
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr Type& operator[](const size_t row, const size_t col) const
|
constexpr const Type& operator[](const size_t row, const size_t col) const
|
||||||
{
|
{
|
||||||
return at(row, col);
|
return at(row, col);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
THIS CODE IS DEPRECATED NEVER EVER USE Matrix CLASS
|
|
||||||
AND VERY SLOW USE Mat INSTEAD!!!!!!!!!!!
|
|
||||||
⠛⠛⣿⣿⣿⣿⣿⡷⢶⣦⣶⣶⣤⣤⣤⣀⠀⠀⠀
|
|
||||||
⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀
|
|
||||||
⠀⠀⠀⠉⠉⠉⠙⠻⣿⣿⠿⠿⠛⠛⠛⠻⣿⣿⣇⠀
|
|
||||||
⠀⠀⢤⣀⣀⣀⠀⠀⢸⣷⡄⠀⣁⣀⣤⣴⣿⣿⣿⣆
|
|
||||||
⠀⠀⠀⠀⠹⠏⠀⠀⠀⣿⣧⠀⠹⣿⣿⣿⣿⣿⡿⣿
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠿⠇⢀⣼⣿⣿⠛⢯⡿⡟
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠦⠴⢿⢿⣿⡿⠷⠀⣿⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠙⣷⣶⣶⣤⣤⣤⣤⣤⣶⣦⠃⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⢐⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀
|
|
||||||
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠻⢿⣿⣿⣿⣿⠟⠁
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef OMATH_ENABLE_LEGACY
|
|
||||||
#include "omath/vector3.hpp"
|
|
||||||
#include <initializer_list>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace omath
|
|
||||||
{
|
|
||||||
|
|
||||||
class Matrix final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Matrix();
|
|
||||||
Matrix(size_t rows, size_t columns);
|
|
||||||
|
|
||||||
Matrix(const std::initializer_list<std::initializer_list<float>>& rows);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static Matrix to_screen_matrix(float screen_width, float screen_height);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static Matrix translation_matrix(const Vector3<float>& diff);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static Matrix orientation_matrix(const Vector3<float>& forward, const Vector3<float>& right,
|
|
||||||
const Vector3<float>& up);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static Matrix projection_matrix(float field_of_view, float aspect_ratio, float near, float far);
|
|
||||||
|
|
||||||
Matrix(const Matrix& other);
|
|
||||||
|
|
||||||
Matrix(size_t rows, size_t columns, const float* raw_data);
|
|
||||||
|
|
||||||
Matrix(Matrix&& other) noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
size_t row_count() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
float& operator[](size_t row, size_t column);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
size_t columns_count() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
std::pair<size_t, size_t> size() const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
float& at(size_t row, size_t col);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
float sum();
|
|
||||||
|
|
||||||
void set_data_from_raw(const float* raw_matrix);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
Matrix transpose() const;
|
|
||||||
|
|
||||||
void set(float val);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
const float& at(size_t row, size_t col) const;
|
|
||||||
|
|
||||||
Matrix operator*(const Matrix& other) const;
|
|
||||||
|
|
||||||
Matrix& operator*=(const Matrix& other);
|
|
||||||
|
|
||||||
Matrix operator*(float f) const;
|
|
||||||
|
|
||||||
Matrix& operator*=(float f);
|
|
||||||
|
|
||||||
Matrix& operator/=(float f);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
Matrix strip(size_t row, size_t column) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
float minor(size_t i, size_t j) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
float alg_complement(size_t i, size_t j) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
float determinant() const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
const float* raw() const;
|
|
||||||
|
|
||||||
Matrix& operator=(const Matrix& other);
|
|
||||||
|
|
||||||
Matrix& operator=(Matrix&& other) noexcept;
|
|
||||||
|
|
||||||
Matrix operator/(float f) const;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
std::string to_string() const;
|
|
||||||
|
|
||||||
~Matrix();
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t m_rows;
|
|
||||||
size_t m_columns;
|
|
||||||
std::unique_ptr<float[]> m_data;
|
|
||||||
};
|
|
||||||
} // namespace omath
|
|
||||||
#endif
|
|
||||||
@@ -4,13 +4,18 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "omath/projection/error_codes.hpp"
|
|
||||||
#include "omath/linear_algebra/mat.hpp"
|
#include "omath/linear_algebra/mat.hpp"
|
||||||
#include "omath/linear_algebra/vector3.hpp"
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
|
#include "omath/projection/error_codes.hpp"
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <omath/angle.hpp>
|
#include <omath/angle.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifdef OMATH_BUILD_TESTS
|
||||||
|
// ReSharper disable once CppInconsistentNaming
|
||||||
|
class UnitTestProjection_Projection_Test;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace omath::projection
|
namespace omath::projection
|
||||||
{
|
{
|
||||||
class ViewPort final
|
class ViewPort final
|
||||||
@@ -45,6 +50,9 @@ namespace omath::projection
|
|||||||
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
requires CameraEngineConcept<TraitClass, Mat4X4Type, ViewAnglesType>
|
||||||
class Camera final
|
class Camera final
|
||||||
{
|
{
|
||||||
|
#ifdef OMATH_BUILD_TESTS
|
||||||
|
friend UnitTestProjection_Projection_Test;
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
~Camera() = default;
|
~Camera() = default;
|
||||||
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
Camera(const Vector3<float>& position, const ViewAnglesType& view_angles, const ViewPort& view_port,
|
||||||
@@ -164,6 +172,38 @@ namespace omath::projection
|
|||||||
|
|
||||||
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
|
return Vector3<float>{projected.at(0, 0), projected.at(1, 0), projected.at(2, 0)};
|
||||||
}
|
}
|
||||||
|
[[nodiscard]]
|
||||||
|
std::expected<Vector3<float>, Error> view_port_to_screen(const Vector3<float>& ndc) const noexcept
|
||||||
|
{
|
||||||
|
const auto inv_view_proj = get_view_projection_matrix().inverted();
|
||||||
|
|
||||||
|
if (!inv_view_proj)
|
||||||
|
return std::unexpected(Error::INV_VIEW_PROJ_MAT_DET_EQ_ZERO);
|
||||||
|
|
||||||
|
auto inverted_projection =
|
||||||
|
inv_view_proj.value() * mat_column_from_vector<float, Mat4X4Type::get_store_ordering()>(ndc);
|
||||||
|
|
||||||
|
if (!inverted_projection.at(3, 0))
|
||||||
|
return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS);
|
||||||
|
|
||||||
|
inverted_projection /= inverted_projection.at(3, 0);
|
||||||
|
|
||||||
|
return Vector3<float>{inverted_projection.at(0, 0), inverted_projection.at(1, 0),
|
||||||
|
inverted_projection.at(2, 0)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::expected<Vector3<float>, Error> screen_to_world(const Vector3<float>& screen_pos) const noexcept
|
||||||
|
{
|
||||||
|
return view_port_to_screen(screen_to_ndc(screen_pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::expected<Vector3<float>, Error> screen_to_world(const Vector2<float>& screen_pos) const noexcept
|
||||||
|
{
|
||||||
|
const auto& [x, y] = screen_pos;
|
||||||
|
return screen_to_world({x, y, 1.f});
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ViewPort m_view_port{};
|
ViewPort m_view_port{};
|
||||||
@@ -186,19 +226,25 @@ namespace omath::projection
|
|||||||
|
|
||||||
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
|
[[nodiscard]] Vector3<float> ndc_to_screen_position(const Vector3<float>& ndc) const noexcept
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
^
|
^
|
||||||
| y
|
| y
|
||||||
1 |
|
1 |
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
-1 ---------0--------- 1 --> x
|
-1 ---------0--------- 1 --> x
|
||||||
|
|
|
|
||||||
|
|
|
|
||||||
-1 |
|
-1 |
|
||||||
v
|
v
|
||||||
*/
|
*/
|
||||||
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
|
return {(ndc.x + 1.f) / 2.f * m_view_port.m_width, (1.f - ndc.y) / 2.f * m_view_port.m_height, ndc.z};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Vector3<float> screen_to_ndc(const Vector3<float>& screen_pos) const noexcept
|
||||||
|
{
|
||||||
|
return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, 1.f - screen_pos.y / m_view_port.m_height * 2.f,
|
||||||
|
screen_pos.z};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace omath::projection
|
} // namespace omath::projection
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ namespace omath::projection
|
|||||||
enum class Error : uint16_t
|
enum class Error : uint16_t
|
||||||
{
|
{
|
||||||
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
|
WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS,
|
||||||
|
INV_VIEW_PROJ_MAT_DET_EQ_ZERO,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -50,12 +50,10 @@ namespace omath::collision
|
|||||||
|
|
||||||
const auto t_hit = side_b.dot(q) * inv_det;
|
const auto t_hit = side_b.dot(q) * inv_det;
|
||||||
|
|
||||||
if (ray.infinite_length)
|
if (ray.infinite_length && t_hit <= k_epsilon)
|
||||||
{
|
return ray.end;
|
||||||
if (t_hit <= k_epsilon)
|
|
||||||
return ray.end;
|
if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
|
||||||
}
|
|
||||||
else if (t_hit <= k_epsilon || t_hit > 1.0f - k_epsilon)
|
|
||||||
return ray.end;
|
return ray.end;
|
||||||
|
|
||||||
return ray.start + ray_dir * t_hit;
|
return ray.start + ray_dir * t_hit;
|
||||||
|
|||||||
@@ -1,364 +0,0 @@
|
|||||||
#ifdef OMATH_ENABLE_LEGACY
|
|
||||||
|
|
||||||
#include "omath/matrix.hpp"
|
|
||||||
#include "omath/angles.hpp"
|
|
||||||
#include "omath/vector3.hpp"
|
|
||||||
#include <complex>
|
|
||||||
#include <format>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace omath
|
|
||||||
{
|
|
||||||
Matrix::Matrix(const size_t rows, const size_t columns)
|
|
||||||
{
|
|
||||||
if (rows == 0 and columns == 0)
|
|
||||||
throw std::runtime_error("Matrix cannot be 0x0");
|
|
||||||
|
|
||||||
m_rows = rows;
|
|
||||||
m_columns = columns;
|
|
||||||
|
|
||||||
m_data = std::make_unique<float[]>(m_rows * m_columns);
|
|
||||||
|
|
||||||
set(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix::Matrix(const std::initializer_list<std::initializer_list<float>>& rows)
|
|
||||||
{
|
|
||||||
m_rows = rows.size();
|
|
||||||
m_columns = rows.begin()->size();
|
|
||||||
|
|
||||||
for (const auto& row: rows)
|
|
||||||
if (row.size() != m_columns)
|
|
||||||
throw std::invalid_argument("All rows must have the same number of columns.");
|
|
||||||
|
|
||||||
m_data = std::make_unique<float[]>(m_rows * m_columns);
|
|
||||||
|
|
||||||
size_t i = 0;
|
|
||||||
for (const auto& row: rows)
|
|
||||||
{
|
|
||||||
size_t j = 0;
|
|
||||||
for (const auto& value: row)
|
|
||||||
at(i, j++) = value;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix::Matrix(const Matrix& other)
|
|
||||||
{
|
|
||||||
m_rows = other.m_rows;
|
|
||||||
m_columns = other.m_columns;
|
|
||||||
|
|
||||||
m_data = std::make_unique<float[]>(m_rows * m_columns);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
at(i, j) = other.at(i, j);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix::Matrix(const size_t rows, const size_t columns, const float* raw_data)
|
|
||||||
{
|
|
||||||
m_rows = rows;
|
|
||||||
m_columns = columns;
|
|
||||||
|
|
||||||
m_data = std::make_unique<float[]>(m_rows * m_columns);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < rows * columns; ++i)
|
|
||||||
at(i / rows, i % columns) = raw_data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Matrix::row_count() const noexcept
|
|
||||||
{
|
|
||||||
return m_rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
float& Matrix::operator[](const size_t row, const size_t column)
|
|
||||||
{
|
|
||||||
return at(row, column);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix::Matrix(Matrix&& other) noexcept
|
|
||||||
{
|
|
||||||
m_rows = other.m_rows;
|
|
||||||
m_columns = other.m_columns;
|
|
||||||
m_data = std::move(other.m_data);
|
|
||||||
|
|
||||||
other.m_rows = 0;
|
|
||||||
other.m_columns = 0;
|
|
||||||
|
|
||||||
other.m_data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Matrix::columns_count() const noexcept
|
|
||||||
{
|
|
||||||
return m_columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<size_t, size_t> Matrix::size() const noexcept
|
|
||||||
{
|
|
||||||
return {row_count(), columns_count()};
|
|
||||||
}
|
|
||||||
|
|
||||||
float& Matrix::at(const size_t row, const size_t col)
|
|
||||||
{
|
|
||||||
return const_cast<float&>(std::as_const(*this).at(row, col));
|
|
||||||
}
|
|
||||||
|
|
||||||
float Matrix::sum()
|
|
||||||
{
|
|
||||||
float sum = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < row_count(); i++)
|
|
||||||
for (size_t j = 0; j < columns_count(); j++)
|
|
||||||
sum += at(i, j);
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float& Matrix::at(const size_t row, const size_t col) const
|
|
||||||
{
|
|
||||||
return m_data[row * m_columns + col];
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::operator*(const Matrix& other) const
|
|
||||||
{
|
|
||||||
if (m_columns != other.m_rows)
|
|
||||||
throw std::runtime_error("n != m");
|
|
||||||
|
|
||||||
auto out_mat = Matrix(m_rows, other.m_columns);
|
|
||||||
|
|
||||||
for (size_t d = 0; d < m_rows; ++d)
|
|
||||||
for (size_t i = 0; i < other.m_columns; ++i)
|
|
||||||
for (size_t j = 0; j < other.m_rows; ++j)
|
|
||||||
out_mat.at(d, i) += at(d, j) * other.at(j, i);
|
|
||||||
|
|
||||||
return out_mat;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix& Matrix::operator*=(const Matrix& other)
|
|
||||||
{
|
|
||||||
*this = *this * other;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::operator*(const float f) const
|
|
||||||
{
|
|
||||||
auto out = *this;
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
out.at(i, j) *= f;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix& Matrix::operator*=(const float f)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < row_count(); i++)
|
|
||||||
for (size_t j = 0; j < columns_count(); j++)
|
|
||||||
at(i, j) *= f;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::clear()
|
|
||||||
{
|
|
||||||
set(0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix& Matrix::operator=(const Matrix& other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
at(i, j) = other.at(i, j);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix& Matrix::operator=(Matrix&& other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
m_rows = other.m_rows;
|
|
||||||
m_columns = other.m_columns;
|
|
||||||
m_data = std::move(other.m_data);
|
|
||||||
|
|
||||||
other.m_rows = 0;
|
|
||||||
other.m_columns = 0;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix& Matrix::operator/=(const float f)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
at(i, j) /= f;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::operator/(const float f) const
|
|
||||||
{
|
|
||||||
auto out = *this;
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
out.at(i, j) /= f;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Matrix::to_string() const
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_rows; i++)
|
|
||||||
{
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
{
|
|
||||||
str += std::format("{:.1f}", at(i, j));
|
|
||||||
|
|
||||||
if (j == m_columns - 1)
|
|
||||||
str += '\n';
|
|
||||||
else
|
|
||||||
str += ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Matrix::determinant() const // NOLINT(*-no-recursion)
|
|
||||||
{
|
|
||||||
if (m_rows + m_columns == 2)
|
|
||||||
return at(0, 0);
|
|
||||||
|
|
||||||
if (m_rows == 2 and m_columns == 2)
|
|
||||||
return at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0);
|
|
||||||
|
|
||||||
float det = 0;
|
|
||||||
for (size_t i = 0; i < m_columns; i++)
|
|
||||||
det += alg_complement(0, i) * at(0, i);
|
|
||||||
|
|
||||||
return det;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Matrix::alg_complement(const size_t i, const size_t j) const // NOLINT(*-no-recursion)
|
|
||||||
{
|
|
||||||
const auto tmp = minor(i, j);
|
|
||||||
return ((i + j + 2) % 2 == 0) ? tmp : -tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::transpose() const
|
|
||||||
{
|
|
||||||
Matrix transposed = {m_columns, m_rows};
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
transposed.at(j, i) = at(i, j);
|
|
||||||
|
|
||||||
return transposed;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix::~Matrix() = default;
|
|
||||||
|
|
||||||
void Matrix::set(const float val)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_rows; ++i)
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
at(i, j) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::strip(const size_t row, const size_t column) const
|
|
||||||
{
|
|
||||||
Matrix stripped = {m_rows - 1, m_columns - 1};
|
|
||||||
size_t strip_row_index = 0;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_rows; i++)
|
|
||||||
{
|
|
||||||
if (i == row)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t strip_column_index = 0;
|
|
||||||
for (size_t j = 0; j < m_columns; ++j)
|
|
||||||
{
|
|
||||||
if (j == column)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
stripped.at(strip_row_index, strip_column_index) = at(i, j);
|
|
||||||
strip_column_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
strip_row_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stripped;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Matrix::minor(const size_t i, const size_t j) const // NOLINT(*-no-recursion)
|
|
||||||
{
|
|
||||||
return strip(i, j).determinant();
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::to_screen_matrix(const float screen_width, const float screen_height)
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
{screen_width / 2.f, 0.f, 0.f, 0.f},
|
|
||||||
{0.f, -screen_height / 2.f, 0.f, 0.f},
|
|
||||||
{0.f, 0.f, 1.f, 0.f},
|
|
||||||
{screen_width / 2.f, screen_height / 2.f, 0.f, 1.f},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::translation_matrix(const Vector3<float>& diff)
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
{1.f, 0.f, 0.f, 0.f},
|
|
||||||
{0.f, 1.f, 0.f, 0.f},
|
|
||||||
{0.f, 0.f, 1.f, 0.f},
|
|
||||||
{diff.x, diff.y, diff.z, 1.f},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::orientation_matrix(const Vector3<float>& forward, const Vector3<float>& right,
|
|
||||||
const Vector3<float>& up)
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
{right.x, up.x, forward.x, 0.f},
|
|
||||||
{right.y, up.y, forward.y, 0.f},
|
|
||||||
{right.z, up.z, forward.z, 0.f},
|
|
||||||
{0.f, 0.f, 0.f, 1.f},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix Matrix::projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
|
|
||||||
const float far)
|
|
||||||
{
|
|
||||||
const float fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / 2.f);
|
|
||||||
|
|
||||||
return {{1.f / (aspect_ratio * fov_half_tan), 0.f, 0.f, 0.f},
|
|
||||||
{0.f, 1.f / fov_half_tan, 0.f, 0.f},
|
|
||||||
{0.f, 0.f, (far + near) / (far - near), 2.f * near * far / (far - near)},
|
|
||||||
{0.f, 0.f, -1.f, 0.f}};
|
|
||||||
}
|
|
||||||
|
|
||||||
const float* Matrix::raw() const
|
|
||||||
{
|
|
||||||
return m_data.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Matrix::set_data_from_raw(const float* raw_matrix)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_columns * m_rows; ++i)
|
|
||||||
at(i / m_rows, i % m_columns) = raw_matrix[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix::Matrix()
|
|
||||||
{
|
|
||||||
m_columns = 0;
|
|
||||||
m_rows = 0;
|
|
||||||
m_data = nullptr;
|
|
||||||
}
|
|
||||||
} // namespace omath
|
|
||||||
#endif
|
|
||||||
@@ -1,3 +1,192 @@
|
|||||||
//
|
//
|
||||||
// Created by Orange on 11/30/2024.
|
// Created by Orange on 11/30/2024.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <numbers>
|
||||||
|
#include <omath/angle.hpp>
|
||||||
|
|
||||||
|
using namespace omath;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// Handy aliases (defaults: Type=float, [0,360], Normalized)
|
||||||
|
using Deg = Angle<float, float(0), float(360), AngleFlags::Normalized>;
|
||||||
|
using Pitch = Angle<float, float(-90), float(90), AngleFlags::Clamped>;
|
||||||
|
using Turn = Angle<float, float(-180), float(180), AngleFlags::Normalized>;
|
||||||
|
|
||||||
|
constexpr float kEps = 1e-5f;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// ---------- Construction / factories ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, DefaultConstructor_IsZeroDegrees)
|
||||||
|
{
|
||||||
|
Deg a; // default ctor
|
||||||
|
EXPECT_FLOAT_EQ(*a, 0.0f);
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, FromDegrees_Normalized_WrapsAboveMax)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_degrees(370.0f);
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, FromDegrees_Normalized_WrapsBelowMin)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_degrees(-10.0f);
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), 350.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, FromDegrees_Clamped_ClampsToRange)
|
||||||
|
{
|
||||||
|
const Pitch hi = Pitch::from_degrees(100.0f);
|
||||||
|
const Pitch lo = Pitch::from_degrees(-120.0f);
|
||||||
|
|
||||||
|
EXPECT_FLOAT_EQ(hi.as_degrees(), 90.0f);
|
||||||
|
EXPECT_FLOAT_EQ(lo.as_degrees(), -90.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, FromRadians_And_AsRadians)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_radians(std::numbers::pi_v<float>);
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), 180.0f);
|
||||||
|
|
||||||
|
const Deg b = Deg::from_degrees(180.0f);
|
||||||
|
EXPECT_NEAR(b.as_radians(), std::numbers::pi_v<float>, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Unary minus & deref ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, UnaryMinus_Normalized)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_degrees(30.0f);
|
||||||
|
const Deg b = -a; // wraps to 330 in [0,360)
|
||||||
|
EXPECT_FLOAT_EQ(b.as_degrees(), 330.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, DereferenceReturnsDegrees)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_degrees(42.0f);
|
||||||
|
EXPECT_FLOAT_EQ(*a, 42.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Trigonometric helpers ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, SinCosTanCot_BasicCases)
|
||||||
|
{
|
||||||
|
const Deg a0 = Deg::from_degrees(0.0f);
|
||||||
|
EXPECT_NEAR(a0.sin(), 0.0f, kEps);
|
||||||
|
EXPECT_NEAR(a0.cos(), 1.0f, kEps);
|
||||||
|
// cot(0) -> cos/sin -> div by 0: allow inf or nan
|
||||||
|
const float cot0 = a0.cot();
|
||||||
|
EXPECT_TRUE(std::isinf(cot0) || std::isnan(cot0));
|
||||||
|
|
||||||
|
const Deg a45 = Deg::from_degrees(45.0f);
|
||||||
|
EXPECT_NEAR(a45.tan(), 1.0f, 1e-4f);
|
||||||
|
EXPECT_NEAR(a45.cot(), 1.0f, 1e-4f);
|
||||||
|
|
||||||
|
const Deg a90 = Deg::from_degrees(90.0f);
|
||||||
|
EXPECT_NEAR(a90.sin(), 1.0f, 1e-4f);
|
||||||
|
EXPECT_NEAR(a90.cos(), 0.0f, 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, Atan_IsAtanOfRadians)
|
||||||
|
{
|
||||||
|
// atan(as_radians). For 0° -> atan(0)=0.
|
||||||
|
const Deg a0 = Deg::from_degrees(0.0f);
|
||||||
|
EXPECT_NEAR(a0.atan(), 0.0f, kEps);
|
||||||
|
|
||||||
|
const Deg a45 = Deg::from_degrees(45.0f);
|
||||||
|
// atan(pi/4) ≈ 0.665773...
|
||||||
|
EXPECT_NEAR(a45.atan(), 0.66577375f, 1e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Compound arithmetic ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, PlusEquals_Normalized_Wraps)
|
||||||
|
{
|
||||||
|
Deg a = Deg::from_degrees(350.0f);
|
||||||
|
a += Deg::from_degrees(20.0f); // 370 -> 10
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, MinusEquals_Normalized_Wraps)
|
||||||
|
{
|
||||||
|
Deg a = Deg::from_degrees(10.0f);
|
||||||
|
a -= Deg::from_degrees(30.0f); // -20 -> 340
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), 340.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, PlusEquals_Clamped_Clamps)
|
||||||
|
{
|
||||||
|
Pitch p = Pitch::from_degrees(80.0f);
|
||||||
|
p += Pitch::from_degrees(30.0f); // 110 -> clamp to 90
|
||||||
|
EXPECT_FLOAT_EQ(p.as_degrees(), 90.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, MinusEquals_Clamped_Clamps)
|
||||||
|
{
|
||||||
|
Pitch p = Pitch::from_degrees(-70.0f);
|
||||||
|
p -= Pitch::from_degrees(40.0f); // -110 -> clamp to -90
|
||||||
|
EXPECT_FLOAT_EQ(p.as_degrees(), -90.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Alternative ranges ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, NormalizedRange_Neg180To180)
|
||||||
|
{
|
||||||
|
const Turn a = Turn::from_degrees(190.0f); // -> -170
|
||||||
|
const Turn b = Turn::from_degrees(-190.0f); // -> 170
|
||||||
|
|
||||||
|
EXPECT_FLOAT_EQ(a.as_degrees(), -170.0f);
|
||||||
|
EXPECT_FLOAT_EQ(b.as_degrees(), 170.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Comparisons (via <=>) ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, Comparisons_WorkWithPartialOrdering)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_degrees(10.0f);
|
||||||
|
const Deg b = Deg::from_degrees(20.0f);
|
||||||
|
const Deg c = Deg::from_degrees(10.0f);
|
||||||
|
|
||||||
|
EXPECT_TRUE(a < b);
|
||||||
|
EXPECT_TRUE(b > a);
|
||||||
|
EXPECT_TRUE(a <= c);
|
||||||
|
EXPECT_TRUE(c >= a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- std::format formatter ----------
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, Formatter_PrintsDegreesWithSuffix)
|
||||||
|
{
|
||||||
|
const Deg a = Deg::from_degrees(15.0f);
|
||||||
|
EXPECT_EQ(std::format("{}", a), "15deg");
|
||||||
|
|
||||||
|
const Deg b = Deg::from_degrees(10.5f);
|
||||||
|
EXPECT_EQ(std::format("{}", b), "10.5deg");
|
||||||
|
|
||||||
|
const Turn t = Turn::from_degrees(-170.0f);
|
||||||
|
EXPECT_EQ(std::format("{}", t), "-170deg");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, BinaryPlus_ReturnsWrappedSum)
|
||||||
|
{
|
||||||
|
Angle<> a = Deg::from_degrees(350.0f);
|
||||||
|
const Deg b = Deg::from_degrees(20.0f);
|
||||||
|
const Deg c = a + b; // expect 10°
|
||||||
|
EXPECT_FLOAT_EQ(c.as_degrees(), 10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UnitTestAngle, BinaryMinus_ReturnsWrappedDiff)
|
||||||
|
{
|
||||||
|
Angle<> a = Deg::from_degrees(10.0f);
|
||||||
|
const Deg b = Deg::from_degrees(30.0f);
|
||||||
|
const Deg c = a - b; // expect 340°
|
||||||
|
EXPECT_FLOAT_EQ(c.as_degrees(), 340.0f);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,184 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by vlad on 5/18/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef OMATH_ENABLE_LEGACY
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <omath/matrix.hpp>
|
|
||||||
#include "omath/vector3.hpp"
|
|
||||||
|
|
||||||
using namespace omath;
|
|
||||||
|
|
||||||
|
|
||||||
class UnitTestMatrix : public ::testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
Matrix m1;
|
|
||||||
Matrix m2;
|
|
||||||
|
|
||||||
void SetUp() override
|
|
||||||
{
|
|
||||||
m1 = Matrix(2, 2);
|
|
||||||
m2 = Matrix{{1.0f, 2.0f}, {3.0f, 4.0f}};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Test constructors
|
|
||||||
TEST_F(UnitTestMatrix, Constructor_Size)
|
|
||||||
{
|
|
||||||
const Matrix m(3, 3);
|
|
||||||
EXPECT_EQ(m.row_count(), 3);
|
|
||||||
EXPECT_EQ(m.columns_count(), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Operator_SquareBrackets)
|
|
||||||
{
|
|
||||||
EXPECT_EQ((m2[0, 0]), 1.0f);
|
|
||||||
EXPECT_EQ((m2[0, 1]), 2.0f);
|
|
||||||
EXPECT_EQ((m2[1, 0]), 3.0f);
|
|
||||||
EXPECT_EQ((m2[1, 1]), 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Constructor_InitializerList)
|
|
||||||
{
|
|
||||||
Matrix m{{1.0f, 2.0f}, {3.0f, 4.0f}};
|
|
||||||
EXPECT_EQ(m.row_count(), 2);
|
|
||||||
EXPECT_EQ(m.columns_count(), 2);
|
|
||||||
EXPECT_FLOAT_EQ(m.at(0, 0), 1.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m.at(1, 1), 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Constructor_Copy)
|
|
||||||
{
|
|
||||||
Matrix m3 = m2;
|
|
||||||
EXPECT_EQ(m3.row_count(), m2.row_count());
|
|
||||||
EXPECT_EQ(m3.columns_count(), m2.columns_count());
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), m2.at(0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Constructor_Move)
|
|
||||||
{
|
|
||||||
Matrix m3 = std::move(m2);
|
|
||||||
EXPECT_EQ(m3.row_count(), 2);
|
|
||||||
EXPECT_EQ(m3.columns_count(), 2);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), 1.0f);
|
|
||||||
EXPECT_EQ(m2.row_count(), 0); // m2 should be empty after the move
|
|
||||||
EXPECT_EQ(m2.columns_count(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test matrix operations
|
|
||||||
TEST_F(UnitTestMatrix, Operator_Multiplication_Matrix)
|
|
||||||
{
|
|
||||||
Matrix m3 = m2 * m2;
|
|
||||||
EXPECT_EQ(m3.row_count(), 2);
|
|
||||||
EXPECT_EQ(m3.columns_count(), 2);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), 7.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(1, 1), 22.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Operator_Multiplication_Scalar)
|
|
||||||
{
|
|
||||||
Matrix m3 = m2 * 2.0f;
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), 2.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(1, 1), 8.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Operator_Division_Scalar)
|
|
||||||
{
|
|
||||||
Matrix m3 = m2 / 2.0f;
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), 0.5f);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(1, 1), 2.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test matrix functions
|
|
||||||
TEST_F(UnitTestMatrix, Transpose)
|
|
||||||
{
|
|
||||||
Matrix m3 = m2.transpose();
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 1), 3.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(1, 0), 2.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Determinant)
|
|
||||||
{
|
|
||||||
const float det = m2.determinant();
|
|
||||||
EXPECT_FLOAT_EQ(det, -2.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Minor)
|
|
||||||
{
|
|
||||||
const float minor = m2.minor(0, 0);
|
|
||||||
EXPECT_FLOAT_EQ(minor, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, AlgComplement)
|
|
||||||
{
|
|
||||||
const float algComp = m2.alg_complement(0, 0);
|
|
||||||
EXPECT_FLOAT_EQ(algComp, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Strip)
|
|
||||||
{
|
|
||||||
Matrix m3 = m2.strip(0, 0);
|
|
||||||
EXPECT_EQ(m3.row_count(), 1);
|
|
||||||
EXPECT_EQ(m3.columns_count(), 1);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, ProjectionMatrix)
|
|
||||||
{
|
|
||||||
const Matrix proj = Matrix::projection_matrix(45.0f, 1.33f, 0.1f, 100.0f);
|
|
||||||
EXPECT_EQ(proj.row_count(), 4);
|
|
||||||
EXPECT_EQ(proj.columns_count(), 4);
|
|
||||||
// Further checks on projection matrix elements could be added
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test other member functions
|
|
||||||
TEST_F(UnitTestMatrix, Set)
|
|
||||||
{
|
|
||||||
m1.set(3.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m1.at(0, 0), 3.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m1.at(1, 1), 3.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Sum)
|
|
||||||
{
|
|
||||||
const float sum = m2.sum();
|
|
||||||
EXPECT_FLOAT_EQ(sum, 10.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, Clear)
|
|
||||||
{
|
|
||||||
m2.clear();
|
|
||||||
EXPECT_FLOAT_EQ(m2.at(0, 0), 0.0f);
|
|
||||||
EXPECT_FLOAT_EQ(m2.at(1, 1), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, ToString)
|
|
||||||
{
|
|
||||||
const std::string str = m2.to_string();
|
|
||||||
EXPECT_FALSE(str.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test assignment operators
|
|
||||||
TEST_F(UnitTestMatrix, AssignmentOperator_Copy)
|
|
||||||
{
|
|
||||||
Matrix m3(2, 2);
|
|
||||||
m3 = m2;
|
|
||||||
EXPECT_EQ(m3.row_count(), m2.row_count());
|
|
||||||
EXPECT_EQ(m3.columns_count(), m2.columns_count());
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), m2.at(0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(UnitTestMatrix, AssignmentOperator_Move)
|
|
||||||
{
|
|
||||||
Matrix m3(2, 2);
|
|
||||||
m3 = std::move(m2);
|
|
||||||
EXPECT_EQ(m3.row_count(), 2);
|
|
||||||
EXPECT_EQ(m3.columns_count(), 2);
|
|
||||||
EXPECT_FLOAT_EQ(m3.at(0, 0), 1.0f);
|
|
||||||
EXPECT_EQ(m2.row_count(), 0); // m2 should be empty after the move
|
|
||||||
EXPECT_EQ(m2.columns_count(), 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -13,8 +13,12 @@ TEST(UnitTestProjection, Projection)
|
|||||||
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
const auto cam = omath::source_engine::Camera({0, 0, 0}, omath::source_engine::ViewAngles{}, {1920.f, 1080.f}, fov,
|
||||||
0.01f, 1000.f);
|
0.01f, 1000.f);
|
||||||
|
|
||||||
const auto projected = cam.world_to_screen({1000, 0, 50});
|
const auto projected = cam.world_to_screen({1000.f, 0, 50.f});
|
||||||
|
const auto result = cam.screen_to_world(projected.value());
|
||||||
|
const auto result2 = cam.world_to_screen(result.value());
|
||||||
|
|
||||||
|
EXPECT_EQ(static_cast<omath::Vector2<float>>(projected.value()),
|
||||||
|
static_cast<omath::Vector2<float>>(result2.value()));
|
||||||
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
EXPECT_NEAR(projected->x, 960.f, 0.001f);
|
||||||
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
EXPECT_NEAR(projected->y, 504.f, 0.001f);
|
||||||
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
EXPECT_NEAR(projected->z, 1.f, 0.001f);
|
||||||
|
|||||||
Reference in New Issue
Block a user